Personal Stories

Stories about how you have used Maple, MapleSim and Math in your life or work.

 

The link below goes to the Proceedings of the Maple 2024 Conference, which includes several articles that will be of interest to the readers of Maple Primes.

There may be one more paper coming in to the proceedings later as per policy; since most things are ready, away we go!

Proceedings of the Maple 2024 Conferenc

 

For a long time, triggered by a disagreement with one of my teachers, I wanted to demonstrate that Euler equations are not absolutely necessary to reproduce gyroscopic effects. Back then, there were no computer tools like Maple or programming languages with powerful libraries like Python. Propper calculations by hand (combining Newton’s equations and vector calculus) would have required days without guarantee of immediate success. Overall, costs and risks were too high to go into an academic argument with someone in charge of grading students.

Some years ago, I remembered the unfinished discussion with my teacher and simulated with MapleSim the simple gyroscope with two point masses that I had in mind at the time. It took only 10 minutes to demonstrate that I was right. At least I thought so. As I discovered recently when investigating the intermediate axis theorem, MapleSim derives behind the scenes Euler equations. This devalued the demonstration.

This post is about a second and successful attempt of a demonstration with Maple employing Lagrangian mechanics.  A rotating system of three point masses connected by rigid struts is used. The animation below from the attached Maple worksheet exactly reproduces a simulation of an equivalent T-shaped structure of three identical masses presented here.

 

Lagrangian Mechanics

The worksheet uses Lagrangian mechanics to derive equations of motion. Only translational energy terms are used in the Lagrangian to prevent Euler equations from being derived. To account for the bound motion of the three point masses, geometric constraints with Lagrange multipliers were added to the Lagrangian L of the system. This lead to a modified Lagrangian Lthat can be used with dedicated Maple commands to derive with little effort a set of Lagrange’s equations of the first kind and the corresponding constraints

Ein Bild, das Text, Schrift, weiß, Reihe enthält.

KI-generierte Inhalte können fehlerhaft sein.

     Ein Bild, das Schrift, Handschrift, Text, Typografie enthält.

KI-generierte Inhalte können fehlerhaft sein.

(source https://en.wikipedia.org/wiki/Lagrangian_mechanics)

For the system of three point masses the above equations lead to 9 coupled second-order ordinary differential equations (ODEs) and 3 algebraic constraints 

(Maple output from the command Physics,LagrangeEquations)

where xi, yi and zi are the components of the position vectors i of the masses 1 to 3 and the li,j are the constraints between the masses i and j, and b and h are the base and the height of the triangle.

The 12 equations together are also referred to as differential algebraic equations (DAEs). Maple has dedicated solvers for such systems which make implementation easy. The most difficult part is setting the initial conditions for all point masses. In this respect MapleSim is even easier to use since not all initial conditions have to be exactly defined by the user. MapleSim also detects constraints that allow for a simplification of the problem by reducing the number of variables to solve. This leads automatically to 3 instead of 12 equations to be solved. Computational effort is reduced in this way significantly.

 

Newtonian Mechanics

One could argue now that the above is a demonstration with Lagrangian mechanics and not with Newtonian mechanics. To treat the system in a Newtonian way, the masses must be isolated and internal forces acting on each mass via the struts are applied to each mass and effectively become external forces. This leads to 9 ODEs with 27 unknows

Ein Bild, das Text, Schrift, Screenshot enthält.

KI-generierte Inhalte können fehlerhaft sein.

Following actio=reactio for each of the (massless) struts reduces the number of unknows to 18

Ein Bild, das Text, Handschrift, Schrift enthält.

KI-generierte Inhalte können fehlerhaft sein.

To solve for the 18 unknows, 9 more relations are required. 3 algebraic constraints that keep the distance between the masses constant have already been listed in the previous section. 6 further algebraic constraints can be established from the fact that the force vectors point towards the opposing mass (see also below).
The effort to solve this system of equations will be even greater but with the benefit of having information about the internal forces in the system.
Before making this effort, it is advisable to take a closer look at the equations of motion derived so far.

 

Forces and the "mysterious" Lagrange Multipliers

Rearranging equations of motion from Lagrangian mechanics to

Ein Bild, das Text, Schrift, Screenshot, Electric Blue (Farbe) enthält.

KI-generierte Inhalte können fehlerhaft sein.

and comparing this to the equations of motion from Newtonian mechanics yields in vector notation 

or more general for the forces

Ein Bild, das Schrift, Handschrift, Reihe, Typografie enthält.

KI-generierte Inhalte können fehlerhaft sein.

where the i are the position vectors of the individual masses and the  are the constraint forces between them.  

In the case of a triangle formed by struts all internal forces must act in the direction of the edges of the triangle. If they would not act this way, opposing pairs of  and   would create a torque around the struts which would lead to an infinite angular acceleration of the massless struts. The above equation confirms this reasoning: The internal forces act in the direction of the difference vectors between the position vectors of the masses (which describe the edges) and scale with lij.

The beauty of the Lagrange multipliers in this case is that they hit 3 birds (three components of the vectors ) with one stone. This reduces the number of unknowns.

However, the Lagrange multipliers are somehow mysterious because they do not represent a physical quantity, but they can be used to calculate meaningful and correct physical results.

What makes them even more mysterious is the fact that positions constraints can be expressed in different ways. In the above example the square of the distance between the masses is kept constant instead of the distance. There are many more possibilities to formulate the constraint of constant distance and each of them results in different multipliers lij with different units. In principle they should all work equivalently but might not all be usable with dedicated solvers.

According to the above equation, the internal forces in a strut scale with the Lagrange multipliers and the length of the strut. During the back and forth flip of the triangle in the above animation the forces vary which can be appreciated from the lij in the following plot. 

Ein Bild, das Diagramm, Reihe enthält.

KI-generierte Inhalte können fehlerhaft sein.

Some observations:

  • At the start, only the strut between the red and the green masses is tensed by centrifugal forces. This would have been intuitively expected.
  • At the start, the broken symmetry in the initial conditions is already visible by the imbalance of the forces in the two other struts.
  • At no time two forces are zero
  • There is never compression in two struts at the same time. The existence of compression forces renders any attempt to replace the struts by cables useless
  • Plotted together in 3D the Lagrange multipliers describe a seemingly perfect circle.

Ein Bild, das Diagramm, Reihe, Kreis, Origami enthält.

KI-generierte Inhalte können fehlerhaft sein.

The last observation in particular shows that both the Lagrange multipliers and the IAT still hold some secrets that need to be clarified:

  • Is it an exact circle? How to prove that?
  • Does a circle appear for all initial conditions and geometries (obtuse isosceles triangles) when the intermediate axis theorem manifests?
  • What does the circle represent? Is it a kind of an invariant between the Lagrange multipliers that allows the calculation of one force when the two others are known?
  • Is there an analytical representation of the circle as a function of the geometry and the initial conditions?
  • What determines the center, the radius and the orientation of the circle?

 

Conclusion

Overall, the approach of adding non-physical terms that are zero to a physical quantity (the difference between kinetic and potential energy) to derive something meaningful is not obvious at all and underlines the genius of Lagrange. For a system of three bound masses it could be used to calculate internal forces as opposed to the more common use of calculating external constraint forces. Beyond the lack of fully satisfying intuitive explanations, the IAT still offers unanswered scientific questions.

 

PS.: 

  • The exercise was a nice cross-check of MapleSim and Maple.
  • dsolve and odeplot are awsome

 

IAT_without_Euler_equations.mw

L. B. Johnson once said: “I may not know much, but I know chicken sh#t from chicken salad.” And the same goes for mathematical software,  Maple is a good chicken salad.

These two numbers can be used to factor two previously factored RSA Challenge numbers:

4492372899485266683229032112393311539091890452003150017722229708882931615085372733373343061967162688807713966063216561545461119244883848142568154156987418243095913219694108294875951005535802313105656690937568115044857082104972025


252470349467980886727391223577367145704558455488893488785280129051457755334632136343591527439288590916228345021218177497619016135424030834870037054353008183582467637830682000623550252325843511739294850378626625818394419012275747807

I'm curious to see if anyone can identify the numbers and do the factorization. If no one has been able to solve this, I will post the solution context at a future date. There exists some very interesting mathematics behind this question that goes beyond a simple recreational diversion.
 

As a university-level math student, I am constantly working through practice problems. An issue I constantly face is that when I get a problem wrong, it can be challenging to find out which line I did wrong. Even if I use Maple Calculator or Maple Learn to get the full steps for a solution, it can be tedious to compare my answer to the steps to see where I went wrong.

 

This is why Check My Work is one of the most popular features in Maple Learn. Check My Work will check all the lines in your solution and give you feedback showing you exactly where you went wrong. I honestly didn’t know that something like this existed until I started here at Maplesoft, and it is now easy to see why this has been one of our most successful features in Maple Learn.

 

Students have been loving it, but the only real complaint is that it’s only available in Maple Learn. So, if you were working on paper, you'd either have to retype your work into Maple Learn or take a picture of your steps using Maple Calculator and then access it in Maple Learn. Something I immediately thought was, if I’m already on my phone to take a picture, I’d much rather be able to stay on my phone.

 

And now you can! Check My Work is now fully available within Maple Calculator!

 

To use Check My Work, all you need to do is take a picture of your solution to a math problem.

 

 

Check My Work will recognize poor handwriting, so there is no need to worry about getting it perfect. After taking the picture, select the Check My Work dropdown in the results screen to see if your solution is correct or where you made a mistake.

 

 

Check My Work will go through your solution line-by-line giving you valuable feedback along the way! Additionally, if you make a mistake, Maple Calculator will point out the line with the error and then proceed with checking the remainder of the solution given this context.  

 

For students, Check My Work is the perfect tool to help you understand and master concepts from class. As a student myself, I’ll for sure be using this feature in my future courses to double-check my work.

 

What makes Check My Work great for learning a technique is that it doesn’t tell you what mistake you made, but rather where the mistake has been made. This is helpful since as a student you don’t have to worry about the time-consuming task of finding the step with an error, but rather you can focus on the learning aspect of actually figuring out what you did wrong.

 

Once you have made corrections to your work on paper, take a new picture and repeat the process. You can also make changes to your solution in-app by clicking the “Check my work in editor” button in the bottom right, which runs Check My Work in the editor where you can modify your solution.

 

No other math tool has a Check My Work feature, and we are very proud to bring this very useful tool to students. By bringing it fully into Maple Calculator, we continue working towards our goal of helping students learn and understand math.

 

View the GIF below for a brief demonstration of how to use Check My Work!

 

 

We hope you enjoy Check My Work in Maple Calculator and let us know what you think!

I teach math at the high school level.

I am worried that Maple 2025 appears to be slower than Maple 2024 - in particular for students with older, less strong laptops.

Maple 2025 takes 50% longer to start than Maple 2024 (or Maple 2025 Screen Reader which I expect to be using).

So, on more sluggist student laptops I fear the slowness overall will be an issue - in particular as Maple regularly has to be shutdown and restarted for some of those students.

Further, I really miss the "recompute section !" and the "magniffy" icons on the quest access bar. Having "recompute entire worksheet !!!" seems unwise though. I wish you could costumize the quest access bar.

Overall, from a teaching point of view, I am not at all impressed, sadly.

The Maplesoft Physics Updates, introduced over a decade ago, brought with them an innovative concept: to deliver fixes and new developments continuously, as soon as they enter the development version of the Maple library for the next release. A key aspect of this initiative was prioritizing the resolution of issues reported on MaplePrimes, ensuring that fixes became available to everyone within 24 to 48 hours. Initially focused solely on the Physics package, the scope of the updates quickly expanded to include other parts of the Maple library and the Typesetting system.

This initiative, which I developed outside regular work hours, aimed to enhance the Maple experience—where issues encountered in daily use could be resolved almost immediately, minimizing disruptions and benefiting the entire user community through shared updates.

As of January 1st, I have stepped away from my role at Maplesoft and have been increasingly involved in activities unrelated to Maple. This raises the question of what will happen with the Physics Updates for Maple 2025 and after.

The Physics project remains a unique and personally meaningful endeavor for me. So, for now, I will continue to dedicate some time to these Updates—but only for the Physics package, not for other parts of the library. As before, these fixes and developments will be included in the Physics Updates only after they have been integrated into the development version of Maple’s official library for the next release. In that sense, they will continue to be Maplesoft updates.

On that note, the first release of the Physics Updates for Maple 2025—focused solely on the Physics package—went out today as version 1854. To install it, the first time open Maple 2025 and use the Maplecloud toolbar -> Packages, or else input PackageTools:-Install(5137472255164416). Any next time, just enter Physics:-Version(latest)

As for fixes beyond the Physics package, I understand that Maplesoft is exploring the possibility of offering something similar to what was previously delivered through the Maplesoft Physics Updates.

All the best

PS: to install the last version of the Maplesoft Physics Updates for Maple 2024, open Maple and input Physics:-Version(1852), not 1853.
 
Edgardo S. Cheb-Terrab
Physics, Differential Equations, and Mathematical Functions
Maplesoft Emmeritus
Research and Education—passionate about all that.

Hello everyone,

I have created a Maple worksheet titled "ΕΜΒΑΔΟΝ ΕΠΙΠΕΔΟΥ ΧΩΡΙΟΥ", designed to help my students prepare for their final exams as they qualify for university. This worksheet focuses on area calculations in plane geometry, using Maple to visualize and solve problems efficiently.

This worksheet is aimed at high school students preparing for university entrance exams, as well as teachers who want to integrate Maple into their teaching.

I would love to hear your thoughts and feedback!

Have you used Maple for similar exam preparation?
εμβαδόν_χωρίου.mw

After a long chat with ChatGPT I finally received a fully working code for a proc for a generalized Woodbury Identity for the inversion of the sum of two or more positive definite matrices.
I was inspired by a family member who is a trained professional programmer, who told me that in his professional work he uses ChatGTP for an initial draft of his program.  
I did find out that ChatGTP makes errors: from simple ones like writing 'Simplify' instead of 'simplify' to serious conceptual errors, for example in recursive loops. However, ChatGTP seems to 'understand' the error after given specific feedback. Although, this does not mean that the next proposal does not contain the same logical error. But after a long chat I received a nice proc that seems to work. 
My second surprise was that Gemini suggested a formula for the generalized Woodbury lemma that was unknown to me, and I was unable to find on Scholar Google or https://math.stackexchange.com. Based on a special case of that formula, I was able to write the second proc myself. 
In conclusion, to start working it can be helpful to collaborate with AI friend, a little patience may help, AI may not be astute as someone on Mapleprimes wrote, but neither am I. I am now retired, and it is fun to play with Maple and AI. 
By the way, the search term Woodbury did not give a single hit on Mapleprimes.With_a_little_help_from_my_friends.mw
kind regards,Harry 

 

 

Maple Transactions Volume 4 Issue 4 has now been published.

 

This issue has two Featured Contributions by people who have been plenary speakers at Maple Conferences in the past, namely Veselin Jungić and Juana Sendra. We hope you enjoy both articles.  There is an accompanying video by Professor Sendra, which we will add a link to when it becomes ready.

As usual, there is an article in the Editor's Corner, but this one is a bit different.  In this one, Michelle Hatzell (the new copyeditor for Maple Transactions, who is also a Masters' student working with me at Western) and I have written about a fun use of Maple's colour contour plots to make an image that might be used as the cover of an upcoming book, namely Perturbation Methods using backward error, which I'm just finishing now with Nic Fillion and which SIAM will publish next year.  So, while there's some math in that paper, it's more about Maple's utilities for colour plotting; so you might find it useful.  We also hope you like at least some of the images.  Some are more attractive than others!

We have several Refereed Contributions, not all of which are ready at this time of publication but which will be added as they are revised and sent in.  We have a nice paper on using continued fractions in a high school context, another on code generation, and another on using Digital Signal Processing in Engineering courses.

Finally we have a first publication in French, by Jalale Soussi.  Actually we have the paper also in English: we chose to publish both, in our Communications section, each with links to the other.  It is possible to publish in Maple Transactions solely in French, of course, but the author provided both, so why not?

Happy reading, and best wishes for 2025. 

In this activity, we are trying to simulate an outbreak of a new infectious disease that our population of 10^6people has not been exposed to before. This means that we are starting with a single case, everyone else is susceptible to the disease, and no one is yet immune or recovered. This can for example reflect a situation where an infected person introduces a new disease into a geographically isolated population, like on an island, or even when an infections "spill over" from other animals into a human population. In terms of the initial conditions for our model, we can define: "S=10^(6) -1=999999," I = 0and R = 0. NULL

Remember, the differential equations for the simple SIR model look like this:

dS/dt = `λS`*dI/dt and `λS`*dI/dt = `λS`-I*gamma, dR/dt = I*gamma

Initial number of people in each compartment
S = 10^6-1",I=0  "and R = 0.

NULL

Parameters:

gamma = .1*recovery*rate*beta and .1*recovery*rate*beta = .4*the*daily*infection*rate

restart; with(plots); _local(gamma)

sys := diff(s(t), t) = -lambda*s(t), diff(i(t), t) = lambda*s(t)-gamma*i(t), diff(r(t), t) = gamma*i(t)

diff(s(t), t) = -lambda*s(t), diff(i(t), t) = lambda*s(t)-gamma*i(t), diff(r(t), t) = gamma*i(t)

(1)

ic := s(0) = s__0, i(0) = i__0, r(0) = r__0

gamma := .1; beta := .4; n := 10^6

.1

 

.4

 

1000000

(2)

lambda := beta*i(t)/n

s__0, i__0, r__0 := 10^6-1, 1, 0

NULL

sols := dsolve({ic, sys}, numeric, output = listprocedure)

display([odeplot(sols, [t, s(t)], 0 .. 100, color = red), odeplot(sols, [t, i(t)], 0 .. 100, color = blue), odeplot(sols, [t, r(t)], 0 .. 100, color = green)], labels = ["Time [day]", "Population"], labeldirections = [horizontal, vertical], legend = ["Susceptible", "Infected", "Recovered"], legendstyle = [location = right])

 

Remember that in a simple homogenous SIR model, `R__eff  `is directly related to the proportion of the population that is susceptible:

R__eff = R__0*S/N

Reff := proc (t) options operator, arrow; beta*s(t)/(gamma*n) end proc

odeplot(sols, [[t, Reff(t)]], t = 0 .. 100, size = [500, 300], labels = ["Time [day]", "Reff"], labeldirections = [horizontal, vertical])

 

The effective reproduction number is highest when everyone is susceptible: at the beginning, `R__eff  ` = R__0. At this point in our example, every infected cases causes an average of 4 secondary infections. Over the course of the epidemic, `R__eff  ` declines in proportion to susceptibility.

The peak of the epidemic happens when `R__eff  ` goes down to 1 (in the example here, after 50 days). As `R__eff  `decreases further below 1, the epidemic prevalence goes into decline. This is exactly what you would expect, given your understanding of the meaning of `R__eff  ` once the epidemic reaches the point where every infected case cannot cause at least one more infected case (that is, when `R__eff  ` < 1), the epidemic cannot sustain itself and comes to an end.

susceptible := eval(s(t), sols); infected := eval(i(t), sols); recovered := eval(r(t), sols)

susceptible(51)

HFloat(219673.04834159758)

(3)

infected(51)

HFloat(401423.4112878752)

(4)

recovered(51)

HFloat(378903.54037052736)

(5)

Reffe := proc (t) options operator, arrow; beta*susceptible(t)/(gamma*n) end proc

proc (t) options operator, arrow; beta*susceptible(t)/(gamma*n) end proc

(6)

Reffe(51)

HFloat(0.8786921933663903)

(7)

Prevalence is simply the value of Iat a given point in time. Now we can see that the incidence is the number of new cases arriving in the I compartment in a given interval of time. The way we represent this mathematically is by taking the integral of new cases over a given duration.

For example, if we wanted to calculate the incidence from day 7 to 14,

int(`&lambda;S`(t), t = 7 .. 14)

lamda := proc (t) options operator, arrow; beta*infected(t)/n end proc

proc (t) options operator, arrow; beta*infected(t)/n end proc

(8)

inflow := proc (t) options operator, arrow; lamda(t)*susceptible(t) end proc

proc (t) options operator, arrow; lamda(t)*susceptible(t) end proc

(9)

int(inflow(t), t = 7 .. 14)

HFloat(78.01804723222038)

(10)

incidence_plot := plot(inflow(t), t = 0 .. 14, color = orange, labels = ["Time (days)", "Incidence Rate"], labeldirections = [horizontal, vertical], title = "Incidence Rate between t=7 and t=14")

 

s, i, r := eval(s(t), sols), eval(i(t), sols), eval(r(t), sols); T := 100; dataArr := Array(-1 .. T, 1 .. 4); dataArr[-1, () .. ()] := `<,>`("Day", "Susceptible", "Infected", "Recovered")


Assign all the subsequent rows

for t from 0 to T do dataArr[t, () .. ()] := `~`[round](`<,>`(t, s(t), i(t), r(t))) end do

 

Tabulate through the DocumentTools

DocumentTools:-Tabulate(dataArr, alignment = left, width = 50, fillcolor = (proc (A, n, m) options operator, arrow; ifelse(n = 1, "DeepSkyBlue", "LightBlue") end proc))

Download dynamics_of_novel_disease_outbreak.mw

I am very happy to announce the first public release of a project which I have been working on for the last couple of years.

NODEMaple consists of a set of Maple workbooks and a library for structural design based on the Eurocode.

Currently the main development of the workbooks is focused on "Eurocode 5: Design of timber structures" with the Norwegian Annex.

This software has been made public in the hope of that it might be useful for other structural designers, professionals as well as students. Everyone interested is very Welcome to contribute to this project. The code is published under the GPLv3 license.

For more information see https://github.com/Anthrazit68/NODEMaple.

I didn't put it in the title, but of course this is a post about Advent of Code, in particular Days 16 and 18 which feature a perenial favorite type of problem: finding shortest paths in mazes.

Your input for these is always a maze given as an ascii map.  Like so:

###############
#.......#....E#
#.#.###.#.###.#
#.....#.#...#.#
#.###.#####.#.#
#.#....#....#.#
#.#.#####.###.#
#...........#.#
###.#.#####.#.#
#...#.....#.#.#
#.#.#.###.#.#.#
#.....#...#.#.#
#.###.#.#.#.#.#
#S......#.#...#
###############

There's lots of ways to import one of these into Maple and then solve the maze, but I am to highlight how to do it with GraphTheory.  I am going to start with a GridGraph and then remove the walls in order to leave a just the vertices that represent the paths:

with(StringTools): with(GraphTheory):
maze:=
"###############
#.......#....E#
#.#.###.#.###.#
#.....#.#...#.#
#.###.#####.#.#
#.#....#....#.#
#.#.#####.###.#
#...........#.#
###.#.#####.#.#
#...#.....#.#.#
#.#.#.###.#.#.#
#.....#...#.#.#
#.###.#.#.#.#.#
#S......#.#...#
###############
":
mazelines := (Split(Trim(maze), "\n")):
sgrid := ListTools:-Reverse((map(Explode, mazelines)) ):
m,n := nops(sgrid), nops(sgrid[1]);
tgrid := table([seq(seq([i,j]=sgrid[i,j],i=1..m),j=1..n)]):
start := lhs(select(e->rhs(e)="S", [entries(tgrid,'pairs')])[]);
finish := lhs(select(e->rhs(e)="E", [entries(tgrid,'pairs')])[]);

Now the maze is stored in the table tgrid, and it is easy to find the walls and paths.  In a GridGraph the vertices are labeled with their coordinates as "x,y" and so we rewrite our list of paths in that form, so we can create the induced subgraph of the Grid that includes only those vertices.

(walls,paths) := selectremove(e->rhs(e)="#", [entries(tgrid, 'pairs')]):
paths := map(s->sprintf("%d,%d",lhs(s)[]), paths):
H := SpecialGraphs:-GridGraph(m,n);
G := InducedSubgraph(H, paths);

We can use StyleVertex to highlight the start and finish.

StyleVertex(G, sprintf("%d,%d",start[]), color="LimeGreen");
StyleVertex(G, sprintf("%d,%d",finish[]), color="Red");

plots:-display(<
DrawGraph(H, stylesheet=[vertexshape="square", vertexborder=false, vertexcolor="Black"], showlabels=false) | 
DrawGraph(G, stylesheet=[vertexshape="square", vertexborder=false, vertexcolor="Black"], showlabels=false)>);

(I omitted a step where I set the vertex locations of the maze grid, you can see that in the attached worksheet)

Now finding a path through the maze is as easy as calling GraphTheory:-ShortestPath

sp := ShortestPath(G, sprintf("%d,%d",start[]), sprintf("%d,%d",finish[]) ):

StyleVertex(G, sp[2..-2], color="Orange");
StyleEdge(G, [seq({sp[i],sp[i+1]}, i=1..nops(sp)-1)], color="Orange");
DrawGraph(G, stylesheet=[vertexshape="square", vertexpadding=10, vertexborder=false,
             vertexcolor="Black"],  showlabels=false, size=[800,800]);

Now, Advent of Code seldom gives you a completely simple maze like this, often these is a twist like having to calculate the costs of turns seperately from the cost of steps, or each direction or position has a seperate cost associated with it.

For example, Day 16 has us starting facing east, and then turns cost 1000, while moving forward costs 1. That sort of problem is no longer exactly a maze, instead of the vertices being representing an "x,y" position, instead you increase the number of vertices by a factor of 4, so that you have a vertex for every position and orientation "x,y,o" with edges of weight 1 between adjacent vertices with the same orientation and edges of wieght 1000 to connect "x,y,N" to "x,y,E" and "x,y,W" e.g.  In that sort of weighted graph, we can use GraphTheory:-DijkstrasAlgorithm to find the shortest path and it's weighted cost.

In this code, we expand our list of maze locations with directions, and the use the grid table to generate a list of weighted edges:

dtable := table([0=[0,1], 1=[1,0], 2=[0,-1], 3=[-1,0]]):
dname := table([0="N",1="E",2="S",3="W"]):
dpaths := map(s->local d;seq(cat(s,",",d), d in ["N","E","S","W"]), paths):

edges := NULL:
for i from 1 to m do for j from 1 to n do
    if tgrid[[i,j]] = "#" then next; end if;
    for d from 0 to 3 do
        dir := dtable[d];
        if tgrid[[i,j]+dir] <> "#" then
            edges := edges, [{cat("",i,",",j,",",dname[d]), cat("",i+dir[1],",",j+dir[2],",",dname[d])},1];
        end if;
        edges := edges, [{cat("",i,",",j,",",dname[d]), cat("",i,",",j,",",dname[d+1 mod 4])}, 1000],
                 [{cat("",i,",",j,",",dname[d]), cat("",i,",",j,",",dname[d-1 mod 4])}, 1000];
    end do;
end do; end do:

Gd := Graph(dpaths,weighted,{edges});

Once that is done, it's a simple matter of calling Dijkstra's Algorithm on the graph, but notice that we can reach the finsh while traveling north or east, so we need to find the sortest path to both (you can pass a list of vertices to Dijkstra, and it will efficiently calculate paths to all of them), and select the smaller of the two:

spds := DijkstrasAlgorithm(Gd, cat("",start[1],",",start[2],",E"), 
    [cat("",finish[1],",",finish[2],",N"), cat("",finish[1],",",finish[2],",E")] , 
    distance):
i := min[index](map2(op,2,spds)):
spd := spds[i];

spd := [["2,2,E", "3,2,E", "4,2,E", "4,2,N", "4,3,N", "4,4,N", "4,5,N", "4,6,N", "4,6,E", "5,6,E",
 "6,6,E", "7,6,E", "8,6,E", "8,6,N", "8,7,N", "8,8,N", "8,9,N", "8,10,N", "8,11,N", "8,12,N", 
"8,12,W", "7,12,W", "6,12,W", "5,12,W", "4,12,W", "3,12,W", "2,12,W", "2,12,N", "2,13,N", 
"2,14,N", "2,14,E", "3,14,E", "4,14,E", "5,14,E", "6,14,E", "7,14,E", "8,14,E", "9,14,E", 
"10,14,E", "11,14,E", "12,14,E", "13,14,E", "14,14,E"], 6036]

We can then plot to compare this to the unweighted shortest path:

dsp := ListTools:-MakeUnique( map(s->s[1..-3], spd[1]) );
StyleVertex(G, dsp[2..-2], color="DarkBlue");
StyleEdge(G, [seq({dsp[i],dsp[i+1]}, i=1..nops(dsp)-1)], color="DarkBlue");

DrawGraph(G, stylesheet=[vertexshape="square", vertexpadding=10,
             vertexborder=false, vertexcolor="Black"],  showlabels=false,
          size=[800,800]);

And you can see it's a path that requires more steps, but definitely uses fewer turns if we start facing east/right (6 vs. 9):

I hope this has given you a little bit of a flavor of how to use GraphTheory commands to solve path finding problems.  Like with the second part here, usually the biggest challenge is figuring out how to encode and construct a graph that represents your problem.  Then the actual commands to solve it, are easy. You can see all the code, and a couple steps I left out from above in this worksheet: Mazeblog.mw

And just for fun, here's a Maple workbook that imports a maze from an image and solves it: MazeFromImage.maple

with(ImageTools): with(GraphTheory):

opic := Read("this://DrawnMaze.png"):
Embed(opic);

bwpic := RGBtoGray(opic):
pic := Flip(Transpose(Scale(bwpic, 0.1, 0.1, method = nearest)),horizontal ):

m,n := upperbound(pic);
start := [2,31];
finish := [30,1];

31, 31

 

[2, 31]

 

[30, 1]

(1)

(paths,walls) := selectremove(e->round(rhs(e))=1, [entries(pic, 'pairs')]):
walls := map(s->sprintf("%d,%d",lhs(s)), walls):
paths := map(s->sprintf("%d,%d",lhs(s)), paths):

H := SpecialGraphs:-GridGraph(m,n);
G := InducedSubgraph(H, paths);

GRAPHLN(undirected, unweighted, ["1,1", "1,2", "1,3", "1,4", "1,5", "1,6", "1,7", "1,8", "1,9", "1,10", "1,11", "1,12", "1,13", "1,14", "1,15", "1,16", "1,17", "1,18", "1,19", "1,20", "1,21", "1,22", "1,23", "1,24", "1,25", "1,26", "1,27", "1,28", "1,29", "1,30", "1,31", "2,1", "2,2", "2,3", "2,4", "2,5", "2,6", "2,7", "2,8", "2,9", "2,10", "2,11", "2,12", "2,13", "2,14", "2,15", "2,16", "2,17", "2,18", "2,19", "2,20", "2,21", "2,22", "2,23", "2,24", "2,25", "2,26", "2,27", "2,28", "2,29", "2,30", "2,31", "3,1", "3,2", "3,3", "3,4", "3,5", "3,6", "3,7", "3,8", "3,9", "3,10", "3,11", "3,12", "3,13", "3,14", "3,15", "3,16", "3,17", "3,18", "3,19", "3,20", "3,21", "3,22", "3,23", "3,24", "3,25", "3,26", "3,27", "3,28", "3,29", "3,30", "3,31", "4,1", "4,2", "4,3", "4,4", "4,5", "4,6", "4,7", "4,8", "4,9", "4,10", "4,11", "4,12", "4,13", "4,14", "4,15", "4,16", "4,17", "4,18", "4,19", "4,20", "4,21", "4,22", "4,23", "4,24", "4,25", "4,26", "4,27", "4,28", "4,29", "4,30", "4,31", "5,1", "5,2", "5,3", "5,4", "5,5", "5,6", "5,7", "5,8", "5,9", "5,10", "5,11", "5,12", "5,13", "5,14", "5,15", "5,16", "5,17", "5,18", "5,19", "5,20", "5,21", "5,22", "5,23", "5,24", "5,25", "5,26", "5,27", "5,28", "5,29", "5,30", "5,31", "6,1", "6,2", "6,3", "6,4", "6,5", "6,6", "6,7", "6,8", "6,9", "6,10", "6,11", "6,12", "6,13", "6,14", "6,15", "6,16", "6,17", "6,18", "6,19", "6,20", "6,21", "6,22", "6,23", "6,24", "6,25", "6,26", "6,27", "6,28", "6,29", "6,30", "6,31", "7,1", "7,2", "7,3", "7,4", "7,5", "7,6", "7,7", "7,8", "7,9", "7,10", "7,11", "7,12", "7,13", "7,14", "7,15", "7,16", "7,17", "7,18", "7,19", "7,20", "7,21", "7,22", "7,23", "7,24", "7,25", "7,26", "7,27", "7,28", "7,29", "7,30", "7,31", "8,1", "8,2", "8,3", "8,4", "8,5", "8,6", "8,7", "8,8", "8,9", "8,10", "8,11", "8,12", "8,13", "8,14", "8,15", "8,16", "8,17", "8,18", "8,19", "8,20", "8,21", "8,22", "8,23", "8,24", "8,25", "8,26", "8,27", "8,28", "8,29", "8,30", "8,31", "9,1", "9,2", "9,3", "9,4", "9,5", "9,6", "9,7", "9,8", "9,9", "9,10", "9,11", "9,12", "9,13", "9,14", "9,15", "9,16", "9,17", "9,18", "9,19", "9,20", "9,21", "9,22", "9,23", "9,24", "9,25", "9,26", "9,27", "9,28", "9,29", "9,30", "9,31", "10,1", "10,2", "10,3", "10,4", "10,5", "10,6", "10,7", "10,8", "10,9", "10,10", "10,11", "10,12", "10,13", "10,14", "10,15", "10,16", "10,17", "10,18", "10,19", "10,20", "10,21", "10,22", "10,23", "10,24", "10,25", "10,26", "10,27", "10,28", "10,29", "10,30", "10,31", "11,1", "11,2", "11,3", "11,4", "11,5", "11,6", "11,7", "11,8", "11,9", "11,10", "11,11", "11,12", "11,13", "11,14", "11,15", "11,16", "11,17", "11,18", "11,19", "11,20", "11,21", "11,22", "11,23", "11,24", "11,25", "11,26", "11,27", "11,28", "11,29", "11,30", "11,31", "12,1", "12,2", "12,3", "12,4", "12,5", "12,6", "12,7", "12,8", "12,9", "12,10", "12,11", "12,12", "12,13", "12,14", "12,15", "12,16", "12,17", "12,18", "12,19", "12,20", "12,21", "12,22", "12,23", "12,24", "12,25", "12,26", "12,27", "12,28", "12,29", "12,30", "12,31", "13,1", "13,2", "13,3", "13,4", "13,5", "13,6", "13,7", "13,8", "13,9", "13,10", "13,11", "13,12", "13,13", "13,14", "13,15", "13,16", "13,17", "13,18", "13,19", "13,20", "13,21", "13,22", "13,23", "13,24", "13,25", "13,26", "13,27", "13,28", "13,29", "13,30", "13,31", "14,1", "14,2", "14,3", "14,4", "14,5", "14,6", "14,7", "14,8", "14,9", "14,10", "14,11", "14,12", "14,13", "14,14", "14,15", "14,16", "14,17", "14,18", "14,19", "14,20", "14,21", "14,22", "14,23", "14,24", "14,25", "14,26", "14,27", "14,28", "14,29", "14,30", "14,31", "15,1", "15,2", "15,3", "15,4", "15,5", "15,6", "15,7", "15,8", "15,9", "15,10", "15,11", "15,12", "15,13", "15,14", "15,15", "15,16", "15,17", "15,18", "15,19", "15,20", "15,21", "15,22", "15,23", "15,24", "15,25", "15,26", "15,27", "15,28", "15,29", "15,30", "15,31", "16,1", "16,2", "16,3", "16,4", "16,5", "16,6", "16,7", "16,8", "16,9", "16,10", "16,11", "16,12", "16,13", "16,14", "16,15", "16,16", "16,17", "16,18", "16,19", "16,20", "16,21", "16,22", "16,23", "16,24", "16,25", "16,26", "16,27", "16,28", "16,29", "16,30", "16,31", "17,1", "17,2", "17,3", "17,4", "17,5", "17,6", "17,7", "17,8", "17,9", "17,10", "17,11", "17,12", "17,13", "17,14", "17,15", "17,16", "17,17", "17,18", "17,19", "17,20", "17,21", "17,22", "17,23", "17,24", "17,25", "17,26", "17,27", "17,28", "17,29", "17,30", "17,31", "18,1", "18,2", "18,3", "18,4", "18,5", "18,6", "18,7", "18,8", "18,9", "18,10", "18,11", "18,12", "18,13", "18,14", "18,15", "18,16", "18,17", "18,18", "18,19", "18,20", "18,21", "18,22", "18,23", "18,24", "18,25", "18,26", "18,27", "18,28", "18,29", "18,30", "18,31", "19,1", "19,2", "19,3", "19,4", "19,5", "19,6", "19,7", "19,8", "19,9", "19,10", "19,11", "19,12", "19,13", "19,14", "19,15", "19,16", "19,17", "19,18", "19,19", "19,20", "19,21", "19,22", "19,23", "19,24", "19,25", "19,26", "19,27", "19,28", "19,29", "19,30", "19,31", "20,1", "20,2", "20,3", "20,4", "20,5", "20,6", "20,7", "20,8", "20,9", "20,10", "20,11", "20,12", "20,13", "20,14", "20,15", "20,16", "20,17", "20,18", "20,19", "20,20", "20,21", "20,22", "20,23", "20,24", "20,25", "20,26", "20,27", "20,28", "20,29", "20,30", "20,31", "21,1", "21,2", "21,3", "21,4", "21,5", "21,6", "21,7", "21,8", "21,9", "21,10", "21,11", "21,12", "21,13", "21,14", "21,15", "21,16", "21,17", "21,18", "21,19", "21,20", "21,21", "21,22", "21,23", "21,24", "21,25", "21,26", "21,27", "21,28", "21,29", "21,30", "21,31", "22,1", "22,2", "22,3", "22,4", "22,5", "22,6", "22,7", "22,8", "22,9", "22,10", "22,11", "22,12", "22,13", "22,14", "22,15", "22,16", "22,17", "22,18", "22,19", "22,20", "22,21", "22,22", "22,23", "22,24", "22,25", "22,26", "22,27", "22,28", "22,29", "22,30", "22,31", "23,1", "23,2", "23,3", "23,4", "23,5", "23,6", "23,7", "23,8", "23,9", "23,10", "23,11", "23,12", "23,13", "23,14", "23,15", "23,16", "23,17", "23,18", "23,19", "23,20", "23,21", "23,22", "23,23", "23,24", "23,25", "23,26", "23,27", "23,28", "23,29", "23,30", "23,31", "24,1", "24,2", "24,3", "24,4", "24,5", "24,6", "24,7", "24,8", "24,9", "24,10", "24,11", "24,12", "24,13", "24,14", "24,15", "24,16", "24,17", "24,18", "24,19", "24,20", "24,21", "24,22", "24,23", "24,24", "24,25", "24,26", "24,27", "24,28", "24,29", "24,30", "24,31", "25,1", "25,2", "25,3", "25,4", "25,5", "25,6", "25,7", "25,8", "25,9", "25,10", "25,11", "25,12", "25,13", "25,14", "25,15", "25,16", "25,17", "25,18", "25,19", "25,20", "25,21", "25,22", "25,23", "25,24", "25,25", "25,26", "25,27", "25,28", "25,29", "25,30", "25,31", "26,1", "26,2", "26,3", "26,4", "26,5", "26,6", "26,7", "26,8", "26,9", "26,10", "26,11", "26,12", "26,13", "26,14", "26,15", "26,16", "26,17", "26,18", "26,19", "26,20", "26,21", "26,22", "26,23", "26,24", "26,25", "26,26", "26,27", "26,28", "26,29", "26,30", "26,31", "27,1", "27,2", "27,3", "27,4", "27,5", "27,6", "27,7", "27,8", "27,9", "27,10", "27,11", "27,12", "27,13", "27,14", "27,15", "27,16", "27,17", "27,18", "27,19", "27,20", "27,21", "27,22", "27,23", "27,24", "27,25", "27,26", "27,27", "27,28", "27,29", "27,30", "27,31", "28,1", "28,2", "28,3", "28,4", "28,5", "28,6", "28,7", "28,8", "28,9", "28,10", "28,11", "28,12", "28,13", "28,14", "28,15", "28,16", "28,17", "28,18", "28,19", "28,20", "28,21", "28,22", "28,23", "28,24", "28,25", "28,26", "28,27", "28,28", "28,29", "28,30", "28,31", "29,1", "29,2", "29,3", "29,4", "29,5", "29,6", "29,7", "29,8", "29,9", "29,10", "29,11", "29,12", "29,13", "29,14", "29,15", "29,16", "29,17", "29,18", "29,19", "29,20", "29,21", "29,22", "29,23", "29,24", "29,25", "29,26", "29,27", "29,28", "29,29", "29,30", "29,31", "30,1", "30,2", "30,3", "30,4", "30,5", "30,6", "30,7", "30,8", "30,9", "30,10", "30,11", "30,12", "30,13", "30,14", "30,15", "30,16", "30,17", "30,18", "30,19", "30,20", "30,21", "30,22", "30,23", "30,24", "30,25", "30,26", "30,27", "30,28", "30,29", "30,30", "30,31", "31,1", "31,2", "31,3", "31,4", "31,5", "31,6", "31,7", "31,8", "31,9", "31,10", "31,11", "31,12", "31,13", "31,14", "31,15", "31,16", "31,17", "31,18", "31,19", "31,20", "31,21", "31,22", "31,23", "31,24", "31,25", "31,26", "31,27", "31,28", "31,29", "31,30", "31,31"], Array(1..961, {(1) = {2, 32}, (2) = {1, 3, 33}, (3) = {2, 4, 34}, (4) = {3, 5, 35}, (5) = {4, 6, 36}, (6) = {5, 7, 37}, (7) = {6, 8, 38}, (8) = {7, 9, 39}, (9) = {8, 10, 40}, (10) = {9, 11, 41}, (11) = {10, 12, 42}, (12) = {11, 13, 43}, (13) = {12, 14, 44}, (14) = {13, 15, 45}, (15) = {14, 16, 46}, (16) = {15, 17, 47}, (17) = {16, 18, 48}, (18) = {17, 19, 49}, (19) = {18, 20, 50}, (20) = {19, 21, 51}, (21) = {20, 22, 52}, (22) = {21, 23, 53}, (23) = {22, 24, 54}, (24) = {23, 25, 55}, (25) = {24, 26, 56}, (26) = {25, 27, 57}, (27) = {26, 28, 58}, (28) = {27, 29, 59}, (29) = {28, 30, 60}, (30) = {29, 31, 61}, (31) = {30, 62}, (32) = {1, 33, 63}, (33) = {2, 32, 34, 64}, (34) = {3, 33, 35, 65}, (35) = {4, 34, 36, 66}, (36) = {5, 35, 37, 67}, (37) = {6, 36, 38, 68}, (38) = {7, 37, 39, 69}, (39) = {8, 38, 40, 70}, (40) = {9, 39, 41, 71}, (41) = {10, 40, 42, 72}, (42) = {11, 41, 43, 73}, (43) = {12, 42, 44, 74}, (44) = {13, 43, 45, 75}, (45) = {14, 44, 46, 76}, (46) = {15, 45, 47, 77}, (47) = {16, 46, 48, 78}, (48) = {17, 47, 49, 79}, (49) = {18, 48, 50, 80}, (50) = {19, 49, 51, 81}, (51) = {20, 50, 52, 82}, (52) = {21, 51, 53, 83}, (53) = {22, 52, 54, 84}, (54) = {23, 53, 55, 85}, (55) = {24, 54, 56, 86}, (56) = {25, 55, 57, 87}, (57) = {26, 56, 58, 88}, (58) = {27, 57, 59, 89}, (59) = {28, 58, 60, 90}, (60) = {29, 59, 61, 91}, (61) = {30, 60, 62, 92}, (62) = {31, 61, 93}, (63) = {32, 64, 94}, (64) = {33, 63, 65, 95}, (65) = {34, 64, 66, 96}, (66) = {35, 65, 67, 97}, (67) = {36, 66, 68, 98}, (68) = {37, 67, 69, 99}, (69) = {38, 68, 70, 100}, (70) = {39, 69, 71, 101}, (71) = {40, 70, 72, 102}, (72) = {41, 71, 73, 103}, (73) = {42, 72, 74, 104}, (74) = {43, 73, 75, 105}, (75) = {44, 74, 76, 106}, (76) = {45, 75, 77, 107}, (77) = {46, 76, 78, 108}, (78) = {47, 77, 79, 109}, (79) = {48, 78, 80, 110}, (80) = {49, 79, 81, 111}, (81) = {50, 80, 82, 112}, (82) = {51, 81, 83, 113}, (83) = {52, 82, 84, 114}, (84) = {53, 83, 85, 115}, (85) = {54, 84, 86, 116}, (86) = {55, 85, 87, 117}, (87) = {56, 86, 88, 118}, (88) = {57, 87, 89, 119}, (89) = {58, 88, 90, 120}, (90) = {59, 89, 91, 121}, (91) = {60, 90, 92, 122}, (92) = {61, 91, 93, 123}, (93) = {62, 92, 124}, (94) = {63, 95, 125}, (95) = {64, 94, 96, 126}, (96) = {65, 95, 97, 127}, (97) = {66, 96, 98, 128}, (98) = {67, 97, 99, 129}, (99) = {68, 98, 100, 130}, (100) = {69, 99, 101, 131}, (101) = {70, 100, 102, 132}, (102) = {71, 101, 103, 133}, (103) = {72, 102, 104, 134}, (104) = {73, 103, 105, 135}, (105) = {74, 104, 106, 136}, (106) = {75, 105, 107, 137}, (107) = {76, 106, 108, 138}, (108) = {77, 107, 109, 139}, (109) = {78, 108, 110, 140}, (110) = {79, 109, 111, 141}, (111) = {80, 110, 112, 142}, (112) = {81, 111, 113, 143}, (113) = {82, 112, 114, 144}, (114) = {83, 113, 115, 145}, (115) = {84, 114, 116, 146}, (116) = {85, 115, 117, 147}, (117) = {86, 116, 118, 148}, (118) = {87, 117, 119, 149}, (119) = {88, 118, 120, 150}, (120) = {89, 119, 121, 151}, (121) = {90, 120, 122, 152}, (122) = {91, 121, 123, 153}, (123) = {92, 122, 124, 154}, (124) = {93, 123, 155}, (125) = {94, 126, 156}, (126) = {95, 125, 127, 157}, (127) = {96, 126, 128, 158}, (128) = {97, 127, 129, 159}, (129) = {98, 128, 130, 160}, (130) = {99, 129, 131, 161}, (131) = {100, 130, 132, 162}, (132) = {101, 131, 133, 163}, (133) = {102, 132, 134, 164}, (134) = {103, 133, 135, 165}, (135) = {104, 134, 136, 166}, (136) = {105, 135, 137, 167}, (137) = {106, 136, 138, 168}, (138) = {107, 137, 139, 169}, (139) = {108, 138, 140, 170}, (140) = {109, 139, 141, 171}, (141) = {110, 140, 142, 172}, (142) = {111, 141, 143, 173}, (143) = {112, 142, 144, 174}, (144) = {113, 143, 145, 175}, (145) = {114, 144, 146, 176}, (146) = {115, 145, 147, 177}, (147) = {116, 146, 148, 178}, (148) = {117, 147, 149, 179}, (149) = {118, 148, 150, 180}, (150) = {119, 149, 151, 181}, (151) = {120, 150, 152, 182}, (152) = {121, 151, 153, 183}, (153) = {122, 152, 154, 184}, (154) = {123, 153, 155, 185}, (155) = {124, 154, 186}, (156) = {125, 157, 187}, (157) = {126, 156, 158, 188}, (158) = {127, 157, 159, 189}, (159) = {128, 158, 160, 190}, (160) = {129, 159, 161, 191}, (161) = {130, 160, 162, 192}, (162) = {131, 161, 163, 193}, (163) = {132, 162, 164, 194}, (164) = {133, 163, 165, 195}, (165) = {134, 164, 166, 196}, (166) = {135, 165, 167, 197}, (167) = {136, 166, 168, 198}, (168) = {137, 167, 169, 199}, (169) = {138, 168, 170, 200}, (170) = {139, 169, 171, 201}, (171) = {140, 170, 172, 202}, (172) = {141, 171, 173, 203}, (173) = {142, 172, 174, 204}, (174) = {143, 173, 175, 205}, (175) = {144, 174, 176, 206}, (176) = {145, 175, 177, 207}, (177) = {146, 176, 178, 208}, (178) = {147, 177, 179, 209}, (179) = {148, 178, 180, 210}, (180) = {149, 179, 181, 211}, (181) = {150, 180, 182, 212}, (182) = {151, 181, 183, 213}, (183) = {152, 182, 184, 214}, (184) = {153, 183, 185, 215}, (185) = {154, 184, 186, 216}, (186) = {155, 185, 217}, (187) = {156, 188, 218}, (188) = {157, 187, 189, 219}, (189) = {158, 188, 190, 220}, (190) = {159, 189, 191, 221}, (191) = {160, 190, 192, 222}, (192) = {161, 191, 193, 223}, (193) = {162, 192, 194, 224}, (194) = {163, 193, 195, 225}, (195) = {164, 194, 196, 226}, (196) = {165, 195, 197, 227}, (197) = {166, 196, 198, 228}, (198) = {167, 197, 199, 229}, (199) = {168, 198, 200, 230}, (200) = {169, 199, 201, 231}, (201) = {170, 200, 202, 232}, (202) = {171, 201, 203, 233}, (203) = {172, 202, 204, 234}, (204) = {173, 203, 205, 235}, (205) = {174, 204, 206, 236}, (206) = {175, 205, 207, 237}, (207) = {176, 206, 208, 238}, (208) = {177, 207, 209, 239}, (209) = {178, 208, 210, 240}, (210) = {179, 209, 211, 241}, (211) = {180, 210, 212, 242}, (212) = {181, 211, 213, 243}, (213) = {182, 212, 214, 244}, (214) = {183, 213, 215, 245}, (215) = {184, 214, 216, 246}, (216) = {185, 215, 217, 247}, (217) = {186, 216, 248}, (218) = {187, 219, 249}, (219) = {188, 218, 220, 250}, (220) = {189, 219, 221, 251}, (221) = {190, 220, 222, 252}, (222) = {191, 221, 223, 253}, (223) = {192, 222, 224, 254}, (224) = {193, 223, 225, 255}, (225) = {194, 224, 226, 256}, (226) = {195, 225, 227, 257}, (227) = {196, 226, 228, 258}, (228) = {197, 227, 229, 259}, (229) = {198, 228, 230, 260}, (230) = {199, 229, 231, 261}, (231) = {200, 230, 232, 262}, (232) = {201, 231, 233, 263}, (233) = {202, 232, 234, 264}, (234) = {203, 233, 235, 265}, (235) = {204, 234, 236, 266}, (236) = {205, 235, 237, 267}, (237) = {206, 236, 238, 268}, (238) = {207, 237, 239, 269}, (239) = {208, 238, 240, 270}, (240) = {209, 239, 241, 271}, (241) = {210, 240, 242, 272}, (242) = {211, 241, 243, 273}, (243) = {212, 242, 244, 274}, (244) = {213, 243, 245, 275}, (245) = {214, 244, 246, 276}, (246) = {215, 245, 247, 277}, (247) = {216, 246, 248, 278}, (248) = {217, 247, 279}, (249) = {218, 250, 280}, (250) = {219, 249, 251, 281}, (251) = {220, 250, 252, 282}, (252) = {221, 251, 253, 283}, (253) = {222, 252, 254, 284}, (254) = {223, 253, 255, 285}, (255) = {224, 254, 256, 286}, (256) = {225, 255, 257, 287}, (257) = {226, 256, 258, 288}, (258) = {227, 257, 259, 289}, (259) = {228, 258, 260, 290}, (260) = {229, 259, 261, 291}, (261) = {230, 260, 262, 292}, (262) = {231, 261, 263, 293}, (263) = {232, 262, 264, 294}, (264) = {233, 263, 265, 295}, (265) = {234, 264, 266, 296}, (266) = {235, 265, 267, 297}, (267) = {236, 266, 268, 298}, (268) = {237, 267, 269, 299}, (269) = {238, 268, 270, 300}, (270) = {239, 269, 271, 301}, (271) = {240, 270, 272, 302}, (272) = {241, 271, 273, 303}, (273) = {242, 272, 274, 304}, (274) = {243, 273, 275, 305}, (275) = {244, 274, 276, 306}, (276) = {245, 275, 277, 307}, (277) = {246, 276, 278, 308}, (278) = {247, 277, 279, 309}, (279) = {248, 278, 310}, (280) = {249, 281, 311}, (281) = {250, 280, 282, 312}, (282) = {251, 281, 283, 313}, (283) = {252, 282, 284, 314}, (284) = {253, 283, 285, 315}, (285) = {254, 284, 286, 316}, (286) = {255, 285, 287, 317}, (287) = {256, 286, 288, 318}, (288) = {257, 287, 289, 319}, (289) = {258, 288, 290, 320}, (290) = {259, 289, 291, 321}, (291) = {260, 290, 292, 322}, (292) = {261, 291, 293, 323}, (293) = {262, 292, 294, 324}, (294) = {263, 293, 295, 325}, (295) = {264, 294, 296, 326}, (296) = {265, 295, 297, 327}, (297) = {266, 296, 298, 328}, (298) = {267, 297, 299, 329}, (299) = {268, 298, 300, 330}, (300) = {269, 299, 301, 331}, (301) = {270, 300, 302, 332}, (302) = {271, 301, 303, 333}, (303) = {272, 302, 304, 334}, (304) = {273, 303, 305, 335}, (305) = {274, 304, 306, 336}, (306) = {275, 305, 307, 337}, (307) = {276, 306, 308, 338}, (308) = {277, 307, 309, 339}, (309) = {278, 308, 310, 340}, (310) = {279, 309, 341}, (311) = {280, 312, 342}, (312) = {281, 311, 313, 343}, (313) = {282, 312, 314, 344}, (314) = {283, 313, 315, 345}, (315) = {284, 314, 316, 346}, (316) = {285, 315, 317, 347}, (317) = {286, 316, 318, 348}, (318) = {287, 317, 319, 349}, (319) = {288, 318, 320, 350}, (320) = {289, 319, 321, 351}, (321) = {290, 320, 322, 352}, (322) = {291, 321, 323, 353}, (323) = {292, 322, 324, 354}, (324) = {293, 323, 325, 355}, (325) = {294, 324, 326, 356}, (326) = {295, 325, 327, 357}, (327) = {296, 326, 328, 358}, (328) = {297, 327, 329, 359}, (329) = {298, 328, 330, 360}, (330) = {299, 329, 331, 361}, (331) = {300, 330, 332, 362}, (332) = {301, 331, 333, 363}, (333) = {302, 332, 334, 364}, (334) = {303, 333, 335, 365}, (335) = {304, 334, 336, 366}, (336) = {305, 335, 337, 367}, (337) = {306, 336, 338, 368}, (338) = {307, 337, 339, 369}, (339) = {308, 338, 340, 370}, (340) = {309, 339, 341, 371}, (341) = {310, 340, 372}, (342) = {311, 343, 373}, (343) = {312, 342, 344, 374}, (344) = {313, 343, 345, 375}, (345) = {314, 344, 346, 376}, (346) = {315, 345, 347, 377}, (347) = {316, 346, 348, 378}, (348) = {317, 347, 349, 379}, (349) = {318, 348, 350, 380}, (350) = {319, 349, 351, 381}, (351) = {320, 350, 352, 382}, (352) = {321, 351, 353, 383}, (353) = {322, 352, 354, 384}, (354) = {323, 353, 355, 385}, (355) = {324, 354, 356, 386}, (356) = {325, 355, 357, 387}, (357) = {326, 356, 358, 388}, (358) = {327, 357, 359, 389}, (359) = {328, 358, 360, 390}, (360) = {329, 359, 361, 391}, (361) = {330, 360, 362, 392}, (362) = {331, 361, 363, 393}, (363) = {332, 362, 364, 394}, (364) = {333, 363, 365, 395}, (365) = {334, 364, 366, 396}, (366) = {335, 365, 367, 397}, (367) = {336, 366, 368, 398}, (368) = {337, 367, 369, 399}, (369) = {338, 368, 370, 400}, (370) = {339, 369, 371, 401}, (371) = {340, 370, 372, 402}, (372) = {341, 371, 403}, (373) = {342, 374, 404}, (374) = {343, 373, 375, 405}, (375) = {344, 374, 376, 406}, (376) = {345, 375, 377, 407}, (377) = {346, 376, 378, 408}, (378) = {347, 377, 379, 409}, (379) = {348, 378, 380, 410}, (380) = {349, 379, 381, 411}, (381) = {350, 380, 382, 412}, (382) = {351, 381, 383, 413}, (383) = {352, 382, 384, 414}, (384) = {353, 383, 385, 415}, (385) = {354, 384, 386, 416}, (386) = {355, 385, 387, 417}, (387) = {356, 386, 388, 418}, (388) = {357, 387, 389, 419}, (389) = {358, 388, 390, 420}, (390) = {359, 389, 391, 421}, (391) = {360, 390, 392, 422}, (392) = {361, 391, 393, 423}, (393) = {362, 392, 394, 424}, (394) = {363, 393, 395, 425}, (395) = {364, 394, 396, 426}, (396) = {365, 395, 397, 427}, (397) = {366, 396, 398, 428}, (398) = {367, 397, 399, 429}, (399) = {368, 398, 400, 430}, (400) = {369, 399, 401, 431}, (401) = {370, 400, 402, 432}, (402) = {371, 401, 403, 433}, (403) = {372, 402, 434}, (404) = {373, 405, 435}, (405) = {374, 404, 406, 436}, (406) = {375, 405, 407, 437}, (407) = {376, 406, 408, 438}, (408) = {377, 407, 409, 439}, (409) = {378, 408, 410, 440}, (410) = {379, 409, 411, 441}, (411) = {380, 410, 412, 442}, (412) = {381, 411, 413, 443}, (413) = {382, 412, 414, 444}, (414) = {383, 413, 415, 445}, (415) = {384, 414, 416, 446}, (416) = {385, 415, 417, 447}, (417) = {386, 416, 418, 448}, (418) = {387, 417, 419, 449}, (419) = {388, 418, 420, 450}, (420) = {389, 419, 421, 451}, (421) = {390, 420, 422, 452}, (422) = {391, 421, 423, 453}, (423) = {392, 422, 424, 454}, (424) = {393, 423, 425, 455}, (425) = {394, 424, 426, 456}, (426) = {395, 425, 427, 457}, (427) = {396, 426, 428, 458}, (428) = {397, 427, 429, 459}, (429) = {398, 428, 430, 460}, (430) = {399, 429, 431, 461}, (431) = {400, 430, 432, 462}, (432) = {401, 431, 433, 463}, (433) = {402, 432, 434, 464}, (434) = {403, 433, 465}, (435) = {404, 436, 466}, (436) = {405, 435, 437, 467}, (437) = {406, 436, 438, 468}, (438) = {407, 437, 439, 469}, (439) = {408, 438, 440, 470}, (440) = {409, 439, 441, 471}, (441) = {410, 440, 442, 472}, (442) = {411, 441, 443, 473}, (443) = {412, 442, 444, 474}, (444) = {413, 443, 445, 475}, (445) = {414, 444, 446, 476}, (446) = {415, 445, 447, 477}, (447) = {416, 446, 448, 478}, (448) = {417, 447, 449, 479}, (449) = {418, 448, 450, 480}, (450) = {419, 449, 451, 481}, (451) = {420, 450, 452, 482}, (452) = {421, 451, 453, 483}, (453) = {422, 452, 454, 484}, (454) = {423, 453, 455, 485}, (455) = {424, 454, 456, 486}, (456) = {425, 455, 457, 487}, (457) = {426, 456, 458, 488}, (458) = {427, 457, 459, 489}, (459) = {428, 458, 460, 490}, (460) = {429, 459, 461, 491}, (461) = {430, 460, 462, 492}, (462) = {431, 461, 463, 493}, (463) = {432, 462, 464, 494}, (464) = {433, 463, 465, 495}, (465) = {434, 464, 496}, (466) = {435, 467, 497}, (467) = {436, 466, 468, 498}, (468) = {437, 467, 469, 499}, (469) = {438, 468, 470, 500}, (470) = {439, 469, 471, 501}, (471) = {440, 470, 472, 502}, (472) = {441, 471, 473, 503}, (473) = {442, 472, 474, 504}, (474) = {443, 473, 475, 505}, (475) = {444, 474, 476, 506}, (476) = {445, 475, 477, 507}, (477) = {446, 476, 478, 508}, (478) = {447, 477, 479, 509}, (479) = {448, 478, 480, 510}, (480) = {449, 479, 481, 511}, (481) = {450, 480, 482, 512}, (482) = {451, 481, 483, 513}, (483) = {452, 482, 484, 514}, (484) = {453, 483, 485, 515}, (485) = {454, 484, 486, 516}, (486) = {455, 485, 487, 517}, (487) = {456, 486, 488, 518}, (488) = {457, 487, 489, 519}, (489) = {458, 488, 490, 520}, (490) = {459, 489, 491, 521}, (491) = {460, 490, 492, 522}, (492) = {461, 491, 493, 523}, (493) = {462, 492, 494, 524}, (494) = {463, 493, 495, 525}, (495) = {464, 494, 496, 526}, (496) = {465, 495, 527}, (497) = {466, 498, 528}, (498) = {467, 497, 499, 529}, (499) = {468, 498, 500, 530}, (500) = {469, 499, 501, 531}, (501) = {470, 500, 502, 532}, (502) = {471, 501, 503, 533}, (503) = {472, 502, 504, 534}, (504) = {473, 503, 505, 535}, (505) = {474, 504, 506, 536}, (506) = {475, 505, 507, 537}, (507) = {476, 506, 508, 538}, (508) = {477, 507, 509, 539}, (509) = {478, 508, 510, 540}, (510) = {479, 509, 511, 541}, (511) = {480, 510, 512, 542}, (512) = {481, 511, 513, 543}, (513) = {482, 512, 514, 544}, (514) = {483, 513, 515, 545}, (515) = {484, 514, 516, 546}, (516) = {485, 515, 517, 547}, (517) = {486, 516, 518, 548}, (518) = {487, 517, 519, 549}, (519) = {488, 518, 520, 550}, (520) = {489, 519, 521, 551}, (521) = {490, 520, 522, 552}, (522) = {491, 521, 523, 553}, (523) = {492, 522, 524, 554}, (524) = {493, 523, 525, 555}, (525) = {494, 524, 526, 556}, (526) = {495, 525, 527, 557}, (527) = {496, 526, 558}, (528) = {497, 529, 559}, (529) = {498, 528, 530, 560}, (530) = {499, 529, 531, 561}, (531) = {500, 530, 532, 562}, (532) = {501, 531, 533, 563}, (533) = {502, 532, 534, 564}, (534) = {503, 533, 535, 565}, (535) = {504, 534, 536, 566}, (536) = {505, 535, 537, 567}, (537) = {506, 536, 538, 568}, (538) = {507, 537, 539, 569}, (539) = {508, 538, 540, 570}, (540) = {509, 539, 541, 571}, (541) = {510, 540, 542, 572}, (542) = {511, 541, 543, 573}, (543) = {512, 542, 544, 574}, (544) = {513, 543, 545, 575}, (545) = {514, 544, 546, 576}, (546) = {515, 545, 547, 577}, (547) = {516, 546, 548, 578}, (548) = {517, 547, 549, 579}, (549) = {518, 548, 550, 580}, (550) = {519, 549, 551, 581}, (551) = {520, 550, 552, 582}, (552) = {521, 551, 553, 583}, (553) = {522, 552, 554, 584}, (554) = {523, 553, 555, 585}, (555) = {524, 554, 556, 586}, (556) = {525, 555, 557, 587}, (557) = {526, 556, 558, 588}, (558) = {527, 557, 589}, (559) = {528, 560, 590}, (560) = {529, 559, 561, 591}, (561) = {530, 560, 562, 592}, (562) = {531, 561, 563, 593}, (563) = {532, 562, 564, 594}, (564) = {533, 563, 565, 595}, (565) = {534, 564, 566, 596}, (566) = {535, 565, 567, 597}, (567) = {536, 566, 568, 598}, (568) = {537, 567, 569, 599}, (569) = {538, 568, 570, 600}, (570) = {539, 569, 571, 601}, (571) = {540, 570, 572, 602}, (572) = {541, 571, 573, 603}, (573) = {542, 572, 574, 604}, (574) = {543, 573, 575, 605}, (575) = {544, 574, 576, 606}, (576) = {545, 575, 577, 607}, (577) = {546, 576, 578, 608}, (578) = {547, 577, 579, 609}, (579) = {548, 578, 580, 610}, (580) = {549, 579, 581, 611}, (581) = {550, 580, 582, 612}, (582) = {551, 581, 583, 613}, (583) = {552, 582, 584, 614}, (584) = {553, 583, 585, 615}, (585) = {554, 584, 586, 616}, (586) = {555, 585, 587, 617}, (587) = {556, 586, 588, 618}, (588) = {557, 587, 589, 619}, (589) = {558, 588, 620}, (590) = {559, 591, 621}, (591) = {560, 590, 592, 622}, (592) = {561, 591, 593, 623}, (593) = {562, 592, 594, 624}, (594) = {563, 593, 595, 625}, (595) = {564, 594, 596, 626}, (596) = {565, 595, 597, 627}, (597) = {566, 596, 598, 628}, (598) = {567, 597, 599, 629}, (599) = {568, 598, 600, 630}, (600) = {569, 599, 601, 631}, (601) = {570, 600, 602, 632}, (602) = {571, 601, 603, 633}, (603) = {572, 602, 604, 634}, (604) = {573, 603, 605, 635}, (605) = {574, 604, 606, 636}, (606) = {575, 605, 607, 637}, (607) = {576, 606, 608, 638}, (608) = {577, 607, 609, 639}, (609) = {578, 608, 610, 640}, (610) = {579, 609, 611, 641}, (611) = {580, 610, 612, 642}, (612) = {581, 611, 613, 643}, (613) = {582, 612, 614, 644}, (614) = {583, 613, 615, 645}, (615) = {584, 614, 616, 646}, (616) = {585, 615, 617, 647}, (617) = {586, 616, 618, 648}, (618) = {587, 617, 619, 649}, (619) = {588, 618, 620, 650}, (620) = {589, 619, 651}, (621) = {590, 622, 652}, (622) = {591, 621, 623, 653}, (623) = {592, 622, 624, 654}, (624) = {593, 623, 625, 655}, (625) = {594, 624, 626, 656}, (626) = {595, 625, 627, 657}, (627) = {596, 626, 628, 658}, (628) = {597, 627, 629, 659}, (629) = {598, 628, 630, 660}, (630) = {599, 629, 631, 661}, (631) = {600, 630, 632, 662}, (632) = {601, 631, 633, 663}, (633) = {602, 632, 634, 664}, (634) = {603, 633, 635, 665}, (635) = {604, 634, 636, 666}, (636) = {605, 635, 637, 667}, (637) = {606, 636, 638, 668}, (638) = {607, 637, 639, 669}, (639) = {608, 638, 640, 670}, (640) = {609, 639, 641, 671}, (641) = {610, 640, 642, 672}, (642) = {611, 641, 643, 673}, (643) = {612, 642, 644, 674}, (644) = {613, 643, 645, 675}, (645) = {614, 644, 646, 676}, (646) = {615, 645, 647, 677}, (647) = {616, 646, 648, 678}, (648) = {617, 647, 649, 679}, (649) = {618, 648, 650, 680}, (650) = {619, 649, 651, 681}, (651) = {620, 650, 682}, (652) = {621, 653, 683}, (653) = {622, 652, 654, 684}, (654) = {623, 653, 655, 685}, (655) = {624, 654, 656, 686}, (656) = {625, 655, 657, 687}, (657) = {626, 656, 658, 688}, (658) = {627, 657, 659, 689}, (659) = {628, 658, 660, 690}, (660) = {629, 659, 661, 691}, (661) = {630, 660, 662, 692}, (662) = {631, 661, 663, 693}, (663) = {632, 662, 664, 694}, (664) = {633, 663, 665, 695}, (665) = {634, 664, 666, 696}, (666) = {635, 665, 667, 697}, (667) = {636, 666, 668, 698}, (668) = {637, 667, 669, 699}, (669) = {638, 668, 670, 700}, (670) = {639, 669, 671, 701}, (671) = {640, 670, 672, 702}, (672) = {641, 671, 673, 703}, (673) = {642, 672, 674, 704}, (674) = {643, 673, 675, 705}, (675) = {644, 674, 676, 706}, (676) = {645, 675, 677, 707}, (677) = {646, 676, 678, 708}, (678) = {647, 677, 679, 709}, (679) = {648, 678, 680, 710}, (680) = {649, 679, 681, 711}, (681) = {650, 680, 682, 712}, (682) = {651, 681, 713}, (683) = {652, 684, 714}, (684) = {653, 683, 685, 715}, (685) = {654, 684, 686, 716}, (686) = {655, 685, 687, 717}, (687) = {656, 686, 688, 718}, (688) = {657, 687, 689, 719}, (689) = {658, 688, 690, 720}, (690) = {659, 689, 691, 721}, (691) = {660, 690, 692, 722}, (692) = {661, 691, 693, 723}, (693) = {662, 692, 694, 724}, (694) = {663, 693, 695, 725}, (695) = {664, 694, 696, 726}, (696) = {665, 695, 697, 727}, (697) = {666, 696, 698, 728}, (698) = {667, 697, 699, 729}, (699) = {668, 698, 700, 730}, (700) = {669, 699, 701, 731}, (701) = {670, 700, 702, 732}, (702) = {671, 701, 703, 733}, (703) = {672, 702, 704, 734}, (704) = {673, 703, 705, 735}, (705) = {674, 704, 706, 736}, (706) = {675, 705, 707, 737}, (707) = {676, 706, 708, 738}, (708) = {677, 707, 709, 739}, (709) = {678, 708, 710, 740}, (710) = {679, 709, 711, 741}, (711) = {680, 710, 712, 742}, (712) = {681, 711, 713, 743}, (713) = {682, 712, 744}, (714) = {683, 715, 745}, (715) = {684, 714, 716, 746}, (716) = {685, 715, 717, 747}, (717) = {686, 716, 718, 748}, (718) = {687, 717, 719, 749}, (719) = {688, 718, 720, 750}, (720) = {689, 719, 721, 751}, (721) = {690, 720, 722, 752}, (722) = {691, 721, 723, 753}, (723) = {692, 722, 724, 754}, (724) = {693, 723, 725, 755}, (725) = {694, 724, 726, 756}, (726) = {695, 725, 727, 757}, (727) = {696, 726, 728, 758}, (728) = {697, 727, 729, 759}, (729) = {698, 728, 730, 760}, (730) = {699, 729, 731, 761}, (731) = {700, 730, 732, 762}, (732) = {701, 731, 733, 763}, (733) = {702, 732, 734, 764}, (734) = {703, 733, 735, 765}, (735) = {704, 734, 736, 766}, (736) = {705, 735, 737, 767}, (737) = {706, 736, 738, 768}, (738) = {707, 737, 739, 769}, (739) = {708, 738, 740, 770}, (740) = {709, 739, 741, 771}, (741) = {710, 740, 742, 772}, (742) = {711, 741, 743, 773}, (743) = {712, 742, 744, 774}, (744) = {713, 743, 775}, (745) = {714, 746, 776}, (746) = {715, 745, 747, 777}, (747) = {716, 746, 748, 778}, (748) = {717, 747, 749, 779}, (749) = {718, 748, 750, 780}, (750) = {719, 749, 751, 781}, (751) = {720, 750, 752, 782}, (752) = {721, 751, 753, 783}, (753) = {722, 752, 754, 784}, (754) = {723, 753, 755, 785}, (755) = {724, 754, 756, 786}, (756) = {725, 755, 757, 787}, (757) = {726, 756, 758, 788}, (758) = {727, 757, 759, 789}, (759) = {728, 758, 760, 790}, (760) = {729, 759, 761, 791}, (761) = {730, 760, 762, 792}, (762) = {731, 761, 763, 793}, (763) = {732, 762, 764, 794}, (764) = {733, 763, 765, 795}, (765) = {734, 764, 766, 796}, (766) = {735, 765, 767, 797}, (767) = {736, 766, 768, 798}, (768) = {737, 767, 769, 799}, (769) = {738, 768, 770, 800}, (770) = {739, 769, 771, 801}, (771) = {740, 770, 772, 802}, (772) = {741, 771, 773, 803}, (773) = {742, 772, 774, 804}, (774) = {743, 773, 775, 805}, (775) = {744, 774, 806}, (776) = {745, 777, 807}, (777) = {746, 776, 778, 808}, (778) = {747, 777, 779, 809}, (779) = {748, 778, 780, 810}, (780) = {749, 779, 781, 811}, (781) = {750, 780, 782, 812}, (782) = {751, 781, 783, 813}, (783) = {752, 782, 784, 814}, (784) = {753, 783, 785, 815}, (785) = {754, 784, 786, 816}, (786) = {755, 785, 787, 817}, (787) = {756, 786, 788, 818}, (788) = {757, 787, 789, 819}, (789) = {758, 788, 790, 820}, (790) = {759, 789, 791, 821}, (791) = {760, 790, 792, 822}, (792) = {761, 791, 793, 823}, (793) = {762, 792, 794, 824}, (794) = {763, 793, 795, 825}, (795) = {764, 794, 796, 826}, (796) = {765, 795, 797, 827}, (797) = {766, 796, 798, 828}, (798) = {767, 797, 799, 829}, (799) = {768, 798, 800, 830}, (800) = {769, 799, 801, 831}, (801) = {770, 800, 802, 832}, (802) = {771, 801, 803, 833}, (803) = {772, 802, 804, 834}, (804) = {773, 803, 805, 835}, (805) = {774, 804, 806, 836}, (806) = {775, 805, 837}, (807) = {776, 808, 838}, (808) = {777, 807, 809, 839}, (809) = {778, 808, 810, 840}, (810) = {779, 809, 811, 841}, (811) = {780, 810, 812, 842}, (812) = {781, 811, 813, 843}, (813) = {782, 812, 814, 844}, (814) = {783, 813, 815, 845}, (815) = {784, 814, 816, 846}, (816) = {785, 815, 817, 847}, (817) = {786, 816, 818, 848}, (818) = {787, 817, 819, 849}, (819) = {788, 818, 820, 850}, (820) = {789, 819, 821, 851}, (821) = {790, 820, 822, 852}, (822) = {791, 821, 823, 853}, (823) = {792, 822, 824, 854}, (824) = {793, 823, 825, 855}, (825) = {794, 824, 826, 856}, (826) = {795, 825, 827, 857}, (827) = {796, 826, 828, 858}, (828) = {797, 827, 829, 859}, (829) = {798, 828, 830, 860}, (830) = {799, 829, 831, 861}, (831) = {800, 830, 832, 862}, (832) = {801, 831, 833, 863}, (833) = {802, 832, 834, 864}, (834) = {803, 833, 835, 865}, (835) = {804, 834, 836, 866}, (836) = {805, 835, 837, 867}, (837) = {806, 836, 868}, (838) = {807, 839, 869}, (839) = {808, 838, 840, 870}, (840) = {809, 839, 841, 871}, (841) = {810, 840, 842, 872}, (842) = {811, 841, 843, 873}, (843) = {812, 842, 844, 874}, (844) = {813, 843, 845, 875}, (845) = {814, 844, 846, 876}, (846) = {815, 845, 847, 877}, (847) = {816, 846, 848, 878}, (848) = {817, 847, 849, 879}, (849) = {818, 848, 850, 880}, (850) = {819, 849, 851, 881}, (851) = {820, 850, 852, 882}, (852) = {821, 851, 853, 883}, (853) = {822, 852, 854, 884}, (854) = {823, 853, 855, 885}, (855) = {824, 854, 856, 886}, (856) = {825, 855, 857, 887}, (857) = {826, 856, 858, 888}, (858) = {827, 857, 859, 889}, (859) = {828, 858, 860, 890}, (860) = {829, 859, 861, 891}, (861) = {830, 860, 862, 892}, (862) = {831, 861, 863, 893}, (863) = {832, 862, 864, 894}, (864) = {833, 863, 865, 895}, (865) = {834, 864, 866, 896}, (866) = {835, 865, 867, 897}, (867) = {836, 866, 868, 898}, (868) = {837, 867, 899}, (869) = {838, 870, 900}, (870) = {839, 869, 871, 901}, (871) = {840, 870, 872, 902}, (872) = {841, 871, 873, 903}, (873) = {842, 872, 874, 904}, (874) = {843, 873, 875, 905}, (875) = {844, 874, 876, 906}, (876) = {845, 875, 877, 907}, (877) = {846, 876, 878, 908}, (878) = {847, 877, 879, 909}, (879) = {848, 878, 880, 910}, (880) = {849, 879, 881, 911}, (881) = {850, 880, 882, 912}, (882) = {851, 881, 883, 913}, (883) = {852, 882, 884, 914}, (884) = {853, 883, 885, 915}, (885) = {854, 884, 886, 916}, (886) = {855, 885, 887, 917}, (887) = {856, 886, 888, 918}, (888) = {857, 887, 889, 919}, (889) = {858, 888, 890, 920}, (890) = {859, 889, 891, 921}, (891) = {860, 890, 892, 922}, (892) = {861, 891, 893, 923}, (893) = {862, 892, 894, 924}, (894) = {863, 893, 895, 925}, (895) = {864, 894, 896, 926}, (896) = {865, 895, 897, 927}, (897) = {866, 896, 898, 928}, (898) = {867, 897, 899, 929}, (899) = {868, 898, 930}, (900) = {869, 901, 931}, (901) = {870, 900, 902, 932}, (902) = {871, 901, 903, 933}, (903) = {872, 902, 904, 934}, (904) = {873, 903, 905, 935}, (905) = {874, 904, 906, 936}, (906) = {875, 905, 907, 937}, (907) = {876, 906, 908, 938}, (908) = {877, 907, 909, 939}, (909) = {878, 908, 910, 940}, (910) = {879, 909, 911, 941}, (911) = {880, 910, 912, 942}, (912) = {881, 911, 913, 943}, (913) = {882, 912, 914, 944}, (914) = {883, 913, 915, 945}, (915) = {884, 914, 916, 946}, (916) = {885, 915, 917, 947}, (917) = {886, 916, 918, 948}, (918) = {887, 917, 919, 949}, (919) = {888, 918, 920, 950}, (920) = {889, 919, 921, 951}, (921) = {890, 920, 922, 952}, (922) = {891, 921, 923, 953}, (923) = {892, 922, 924, 954}, (924) = {893, 923, 925, 955}, (925) = {894, 924, 926, 956}, (926) = {895, 925, 927, 957}, (927) = {896, 926, 928, 958}, (928) = {897, 927, 929, 959}, (929) = {898, 928, 930, 960}, (930) = {899, 929, 961}, (931) = {900, 932}, (932) = {901, 931, 933}, (933) = {902, 932, 934}, (934) = {903, 933, 935}, (935) = {904, 934, 936}, (936) = {905, 935, 937}, (937) = {906, 936, 938}, (938) = {907, 937, 939}, (939) = {908, 938, 940}, (940) = {909, 939, 941}, (941) = {910, 940, 942}, (942) = {911, 941, 943}, (943) = {912, 942, 944}, (944) = {913, 943, 945}, (945) = {914, 944, 946}, (946) = {915, 945, 947}, (947) = {916, 946, 948}, (948) = {917, 947, 949}, (949) = {918, 948, 950}, (950) = {919, 949, 951}, (951) = {920, 950, 952}, (952) = {921, 951, 953}, (953) = {922, 952, 954}, (954) = {923, 953, 955}, (955) = {924, 954, 956}, (956) = {925, 955, 957}, (957) = {926, 956, 958}, (958) = {927, 957, 959}, (959) = {928, 958, 960}, (960) = {929, 959, 961}, (961) = {930, 960}}), `GRAPHLN/table/1`, 0)

 

GRAPHLN(undirected, unweighted, ["2,2", "2,3", "2,4", "2,5", "2,6", "2,7", "2,8", "2,9", "2,10", "2,11", "2,12", "2,13", "2,14", "2,15", "2,16", "2,18", "2,19", "2,20", "2,21", "2,22", "2,23", "2,24", "2,25", "2,26", "2,27", "2,28", "2,29", "2,30", "2,31", "3,2", "3,16", "3,18", "3,26", "4,2", "4,3", "4,4", "4,5", "4,6", "4,7", "4,8", "4,9", "4,10", "4,11", "4,12", "4,13", "4,14", "4,16", "4,18", "4,19", "4,20", "4,21", "4,22", "4,23", "4,24", "4,26", "4,27", "4,28", "4,29", "4,30", "5,2", "5,14", "5,16", "5,24", "5,30", "6,2", "6,3", "6,4", "6,5", "6,6", "6,7", "6,8", "6,9", "6,10", "6,11", "6,12", "6,14", "6,16", "6,17", "6,18", "6,19", "6,20", "6,21", "6,22", "6,23", "6,24", "6,26", "6,27", "6,28", "6,30", "7,12", "7,14", "7,24", "7,26", "7,28", "7,30", "8,2", "8,3", "8,4", "8,5", "8,6", "8,7", "8,8", "8,9", "8,10", "8,11", "8,12", "8,14", "8,15", "8,16", "8,17", "8,18", "8,19", "8,20", "8,21", "8,22", "8,24", "8,26", "8,28", "8,30", "9,2", "9,22", "9,24", "9,26", "9,28", "9,30", "10,2", "10,4", "10,5", "10,6", "10,7", "10,8", "10,9", "10,10", "10,11", "10,12", "10,13", "10,14", "10,15", "10,16", "10,17", "10,18", "10,20", "10,22", "10,24", "10,26", "10,28", "10,30", "11,2", "11,4", "11,18", "11,20", "11,22", "11,24", "11,26", "11,28", "11,30", "12,2", "12,4", "12,6", "12,7", "12,8", "12,9", "12,10", "12,11", "12,12", "12,13", "12,14", "12,15", "12,16", "12,17", "12,18", "12,20", "12,22", "12,24", "12,26", "12,28", "12,29", "12,30", "13,2", "13,4", "13,6", "13,18", "13,20", "13,22", "13,24", "14,2", "14,4", "14,6", "14,8", "14,9", "14,10", "14,12", "14,13", "14,14", "14,15", "14,16", "14,18", "14,20", "14,22", "14,24", "14,25", "14,26", "14,27", "14,28", "14,29", "14,30", "15,2", "15,4", "15,6", "15,8", "15,10", "15,12", "15,14", "15,16", "15,18", "15,20", "15,22", "15,30", "16,2", "16,3", "16,4", "16,6", "16,8", "16,10", "16,12", "16,14", "16,16", "16,18", "16,20", "16,22", "16,23", "16,24", "16,26", "16,27", "16,28", "16,30", "17,6", "17,8", "17,10", "17,12", "17,14", "17,16", "17,18", "17,20", "17,24", "17,26", "17,28", "17,30", "18,2", "18,3", "18,4", "18,5", "18,6", "18,8", "18,10", "18,12", "18,14", "18,16", "18,18", "18,20", "18,21", "18,22", "18,24", "18,26", "18,28", "18,30", "19,2", "19,8", "19,10", "19,12", "19,14", "19,16", "19,18", "19,20", "19,22", "19,24", "19,26", "19,28", "19,30", "20,2", "20,3", "20,4", "20,5", "20,6", "20,7", "20,8", "20,10", "20,12", "20,14", "20,16", "20,18", "20,20", "20,22", "20,24", "20,26", "20,28", "20,30", "21,10", "21,12", "21,14", "21,16", "21,18", "21,20", "21,22", "21,24", "21,26", "21,28", "21,30", "22,2", "22,3", "22,4", "22,5", "22,6", "22,7", "22,8", "22,9", "22,10", "22,12", "22,14", "22,16", "22,18", "22,20", "22,22", "22,24", "22,26", "22,28", "22,29", "22,30", "23,2", "23,12", "23,14", "23,16", "23,18", "23,20", "23,22", "23,24", "23,26", "24,2", "24,4", "24,5", "24,6", "24,7", "24,8", "24,9", "24,10", "24,11", "24,12", "24,14", "24,16", "24,18", "24,20", "24,22", "24,24", "24,26", "24,27", "24,28", "24,29", "24,30", "25,2", "25,14", "25,16", "25,18", "25,20", "25,22", "25,24", "26,2", "26,4", "26,5", "26,6", "26,7", "26,8", "26,9", "26,10", "26,11", "26,12", "26,14", "26,16", "26,18", "26,20", "26,22", "26,24", "26,25", "26,26", "26,27", "26,28", "26,29", "26,30", "27,2", "27,4", "27,12", "27,14", "27,16", "27,18", "27,20", "27,22", "27,30", "28,2", "28,4", "28,6", "28,7", "28,8", "28,9", "28,10", "28,11", "28,12", "28,14", "28,16", "28,18", "28,20", "28,22", "28,23", "28,24", "28,26", "28,27", "28,28", "28,30", "29,4", "29,6", "29,14", "29,16", "29,18", "29,20", "29,24", "29,26", "29,28", "29,30", "30,1", "30,2", "30,3", "30,4", "30,6", "30,7", "30,8", "30,9", "30,10", "30,11", "30,12", "30,13", "30,14", "30,16", "30,17", "30,18", "30,20", "30,21", "30,22", "30,24", "30,25", "30,26", "30,28", "30,29", "30,30"], Array(1..451, {(1) = {2, 30}, (2) = {1, 3}, (3) = {2, 4}, (4) = {3, 5}, (5) = {4, 6}, (6) = {5, 7}, (7) = {6, 8}, (8) = {7, 9}, (9) = {8, 10}, (10) = {9, 11}, (11) = {10, 12}, (12) = {11, 13}, (13) = {12, 14}, (14) = {13, 15}, (15) = {14, 31}, (16) = {17, 32}, (17) = {16, 18}, (18) = {17, 19}, (19) = {18, 20}, (20) = {19, 21}, (21) = {20, 22}, (22) = {21, 23}, (23) = {22, 24}, (24) = {23, 25, 33}, (25) = {24, 26}, (26) = {25, 27}, (27) = {26, 28}, (28) = {27, 29}, (29) = {28}, (30) = {1, 34}, (31) = {15, 47}, (32) = {16, 48}, (33) = {24, 55}, (34) = {30, 35, 60}, (35) = {34, 36}, (36) = {35, 37}, (37) = {36, 38}, (38) = {37, 39}, (39) = {38, 40}, (40) = {39, 41}, (41) = {40, 42}, (42) = {41, 43}, (43) = {42, 44}, (44) = {43, 45}, (45) = {44, 46}, (46) = {45, 61}, (47) = {31, 62}, (48) = {32, 49}, (49) = {48, 50}, (50) = {49, 51}, (51) = {50, 52}, (52) = {51, 53}, (53) = {52, 54}, (54) = {53, 63}, (55) = {33, 56}, (56) = {55, 57}, (57) = {56, 58}, (58) = {57, 59}, (59) = {58, 64}, (60) = {34, 65}, (61) = {46, 76}, (62) = {47, 77}, (63) = {54, 85}, (64) = {59, 89}, (65) = {60, 66}, (66) = {65, 67}, (67) = {66, 68}, (68) = {67, 69}, (69) = {68, 70}, (70) = {69, 71}, (71) = {70, 72}, (72) = {71, 73}, (73) = {72, 74}, (74) = {73, 75}, (75) = {74, 90}, (76) = {61, 91}, (77) = {62, 78}, (78) = {77, 79}, (79) = {78, 80}, (80) = {79, 81}, (81) = {80, 82}, (82) = {81, 83}, (83) = {82, 84}, (84) = {83, 85}, (85) = {63, 84, 92}, (86) = {87, 93}, (87) = {86, 88}, (88) = {87, 94}, (89) = {64, 95}, (90) = {75, 106}, (91) = {76, 107}, (92) = {85, 116}, (93) = {86, 117}, (94) = {88, 118}, (95) = {89, 119}, (96) = {97, 120}, (97) = {96, 98}, (98) = {97, 99}, (99) = {98, 100}, (100) = {99, 101}, (101) = {100, 102}, (102) = {101, 103}, (103) = {102, 104}, (104) = {103, 105}, (105) = {104, 106}, (106) = {90, 105}, (107) = {91, 108}, (108) = {107, 109}, (109) = {108, 110}, (110) = {109, 111}, (111) = {110, 112}, (112) = {111, 113}, (113) = {112, 114}, (114) = {113, 115}, (115) = {114, 121}, (116) = {92, 122}, (117) = {93, 123}, (118) = {94, 124}, (119) = {95, 125}, (120) = {96, 126}, (121) = {115, 143}, (122) = {116, 144}, (123) = {117, 145}, (124) = {118, 146}, (125) = {119, 147}, (126) = {120, 148}, (127) = {128, 149}, (128) = {127, 129}, (129) = {128, 130}, (130) = {129, 131}, (131) = {130, 132}, (132) = {131, 133}, (133) = {132, 134}, (134) = {133, 135}, (135) = {134, 136}, (136) = {135, 137}, (137) = {136, 138}, (138) = {137, 139}, (139) = {138, 140}, (140) = {139, 141}, (141) = {140, 150}, (142) = {151}, (143) = {121, 152}, (144) = {122, 153}, (145) = {123, 154}, (146) = {124, 155}, (147) = {125, 156}, (148) = {126, 157}, (149) = {127, 158}, (150) = {141, 171}, (151) = {142, 172}, (152) = {143, 173}, (153) = {144, 174}, (154) = {145, 175}, (155) = {146, 176}, (156) = {147, 178}, (157) = {148, 179}, (158) = {149, 180}, (159) = {160, 181}, (160) = {159, 161}, (161) = {160, 162}, (162) = {161, 163}, (163) = {162, 164}, (164) = {163, 165}, (165) = {164, 166}, (166) = {165, 167}, (167) = {166, 168}, (168) = {167, 169}, (169) = {168, 170}, (170) = {169, 171}, (171) = {150, 170, 182}, (172) = {151, 183}, (173) = {152, 184}, (174) = {153, 185}, (175) = {154}, (176) = {155, 177}, (177) = {176, 178}, (178) = {156, 177}, (179) = {157, 186}, (180) = {158, 187}, (181) = {159, 188}, (182) = {171, 197}, (183) = {172, 198}, (184) = {173, 199}, (185) = {174, 200}, (186) = {179, 207}, (187) = {180, 208}, (188) = {181, 209}, (189) = {190, 210}, (190) = {189, 191}, (191) = {190, 211}, (192) = {193, 212}, (193) = {192, 194}, (194) = {193, 195, 213}, (195) = {194, 196}, (196) = {195, 214}, (197) = {182, 215}, (198) = {183, 216}, (199) = {184, 217}, (200) = {185, 201}, (201) = {200, 202}, (202) = {201, 203}, (203) = {202, 204}, (204) = {203, 205}, (205) = {204, 206}, (206) = {205, 218}, (207) = {186, 219}, (208) = {187, 221}, (209) = {188, 222}, (210) = {189, 223}, (211) = {191, 224}, (212) = {192, 225}, (213) = {194, 226}, (214) = {196, 227}, (215) = {197, 228}, (216) = {198, 229}, (217) = {199, 230}, (218) = {206, 236}, (219) = {207, 220}, (220) = {219, 221}, (221) = {208, 220}, (222) = {209, 237}, (223) = {210, 238}, (224) = {211, 239}, (225) = {212, 240}, (226) = {213, 241}, (227) = {214, 242}, (228) = {215, 243}, (229) = {216, 244}, (230) = {217, 231}, (231) = {230, 232}, (232) = {231, 245}, (233) = {234, 246}, (234) = {233, 235}, (235) = {234, 247}, (236) = {218, 248}, (237) = {222, 253}, (238) = {223, 254}, (239) = {224, 255}, (240) = {225, 256}, (241) = {226, 257}, (242) = {227, 258}, (243) = {228, 259}, (244) = {229, 260}, (245) = {232, 263}, (246) = {233, 264}, (247) = {235, 265}, (248) = {236, 266}, (249) = {250, 267}, (250) = {249, 251}, (251) = {250, 252}, (252) = {251, 253}, (253) = {237, 252}, (254) = {238, 268}, (255) = {239, 269}, (256) = {240, 270}, (257) = {241, 271}, (258) = {242, 272}, (259) = {243, 273}, (260) = {244, 261, 274}, (261) = {260, 262}, (262) = {261, 275}, (263) = {245, 276}, (264) = {246, 277}, (265) = {247, 278}, (266) = {248, 279}, (267) = {249, 280}, (268) = {254, 286}, (269) = {255, 287}, (270) = {256, 288}, (271) = {257, 289}, (272) = {258, 290}, (273) = {259, 291}, (274) = {260, 292}, (275) = {262, 293}, (276) = {263, 294}, (277) = {264, 295}, (278) = {265, 296}, (279) = {266, 297}, (280) = {267, 281}, (281) = {280, 282}, (282) = {281, 283}, (283) = {282, 284}, (284) = {283, 285}, (285) = {284, 286}, (286) = {268, 285}, (287) = {269, 298}, (288) = {270, 299}, (289) = {271, 300}, (290) = {272, 301}, (291) = {273, 302}, (292) = {274, 303}, (293) = {275, 304}, (294) = {276, 305}, (295) = {277, 306}, (296) = {278, 307}, (297) = {279, 308}, (298) = {287, 317}, (299) = {288, 318}, (300) = {289, 319}, (301) = {290, 320}, (302) = {291, 321}, (303) = {292, 322}, (304) = {293, 323}, (305) = {294, 324}, (306) = {295, 325}, (307) = {296, 326}, (308) = {297, 328}, (309) = {310, 329}, (310) = {309, 311}, (311) = {310, 312}, (312) = {311, 313}, (313) = {312, 314}, (314) = {313, 315}, (315) = {314, 316}, (316) = {315, 317}, (317) = {298, 316}, (318) = {299, 330}, (319) = {300, 331}, (320) = {301, 332}, (321) = {302, 333}, (322) = {303, 334}, (323) = {304, 335}, (324) = {305, 336}, (325) = {306, 337}, (326) = {307, 327}, (327) = {326, 328}, (328) = {308, 327}, (329) = {309, 338}, (330) = {318, 347}, (331) = {319, 348}, (332) = {320, 349}, (333) = {321, 350}, (334) = {322, 351}, (335) = {323, 352}, (336) = {324, 353}, (337) = {325, 354}, (338) = {329, 359}, (339) = {340}, (340) = {339, 341}, (341) = {340, 342}, (342) = {341, 343}, (343) = {342, 344}, (344) = {343, 345}, (345) = {344, 346}, (346) = {345, 347}, (347) = {330, 346}, (348) = {331, 360}, (349) = {332, 361}, (350) = {333, 362}, (351) = {334, 363}, (352) = {335, 364}, (353) = {336, 365}, (354) = {337, 355}, (355) = {354, 356}, (356) = {355, 357}, (357) = {356, 358}, (358) = {357}, (359) = {338, 366}, (360) = {348, 376}, (361) = {349, 377}, (362) = {350, 378}, (363) = {351, 379}, (364) = {352, 380}, (365) = {353, 381}, (366) = {359, 388}, (367) = {368, 389}, (368) = {367, 369}, (369) = {368, 370}, (370) = {369, 371}, (371) = {370, 372}, (372) = {371, 373}, (373) = {372, 374}, (374) = {373, 375}, (375) = {374, 390}, (376) = {360, 391}, (377) = {361, 392}, (378) = {362, 393}, (379) = {363, 394}, (380) = {364, 395}, (381) = {365, 382}, (382) = {381, 383}, (383) = {382, 384}, (384) = {383, 385}, (385) = {384, 386}, (386) = {385, 387}, (387) = {386, 396}, (388) = {366, 397}, (389) = {367, 398}, (390) = {375, 405}, (391) = {376, 406}, (392) = {377, 407}, (393) = {378, 408}, (394) = {379, 409}, (395) = {380, 410}, (396) = {387, 416}, (397) = {388}, (398) = {389, 417}, (399) = {400, 418}, (400) = {399, 401}, (401) = {400, 402}, (402) = {401, 403}, (403) = {402, 404}, (404) = {403, 405}, (405) = {390, 404}, (406) = {391, 419}, (407) = {392, 420}, (408) = {393, 421}, (409) = {394, 422}, (410) = {395, 411}, (411) = {410, 412}, (412) = {411, 423}, (413) = {414, 424}, (414) = {413, 415}, (415) = {414, 425}, (416) = {396, 426}, (417) = {398, 430}, (418) = {399, 431}, (419) = {406, 439}, (420) = {407, 440}, (421) = {408, 442}, (422) = {409, 443}, (423) = {412, 446}, (424) = {413, 448}, (425) = {415, 449}, (426) = {416, 451}, (427) = {428}, (428) = {427, 429}, (429) = {428, 430}, (430) = {417, 429}, (431) = {418, 432}, (432) = {431, 433}, (433) = {432, 434}, (434) = {433, 435}, (435) = {434, 436}, (436) = {435, 437}, (437) = {436, 438}, (438) = {437, 439}, (439) = {419, 438}, (440) = {420, 441}, (441) = {440, 442}, (442) = {421, 441}, (443) = {422, 444}, (444) = {443, 445}, (445) = {444}, (446) = {423, 447}, (447) = {446, 448}, (448) = {424, 447}, (449) = {425, 450}, (450) = {449, 451}, (451) = {426, 450}}), `GRAPHLN/table/2`, 0)

(2)

G := Graph(Edges(G));

GRAPHLN(undirected, unweighted, ["10,10", "10,11", "10,12", "10,13", "10,14", "10,15", "10,16", "10,17", "10,18", "10,2", "10,20", "10,22", "10,24", "10,26", "10,28", "10,30", "10,4", "10,5", "10,6", "10,7", "10,8", "10,9", "11,18", "11,2", "11,20", "11,22", "11,24", "11,26", "11,28", "11,30", "11,4", "12,10", "12,11", "12,12", "12,13", "12,14", "12,15", "12,16", "12,17", "12,18", "12,2", "12,20", "12,22", "12,24", "12,26", "12,28", "12,29", "12,30", "12,4", "12,6", "12,7", "12,8", "12,9", "13,18", "13,2", "13,20", "13,22", "13,24", "13,4", "13,6", "14,10", "14,12", "14,13", "14,14", "14,15", "14,16", "14,18", "14,2", "14,20", "14,22", "14,24", "14,25", "14,26", "14,27", "14,28", "14,29", "14,30", "14,4", "14,6", "14,8", "14,9", "15,10", "15,12", "15,14", "15,16", "15,18", "15,2", "15,20", "15,22", "15,30", "15,4", "15,6", "15,8", "16,10", "16,12", "16,14", "16,16", "16,18", "16,2", "16,20", "16,22", "16,23", "16,24", "16,26", "16,27", "16,28", "16,3", "16,30", "16,4", "16,6", "16,8", "17,10", "17,12", "17,14", "17,16", "17,18", "17,20", "17,24", "17,26", "17,28", "17,30", "17,6", "17,8", "18,10", "18,12", "18,14", "18,16", "18,18", "18,2", "18,20", "18,21", "18,22", "18,24", "18,26", "18,28", "18,3", "18,30", "18,4", "18,5", "18,6", "18,8", "19,10", "19,12", "19,14", "19,16", "19,18", "19,2", "19,20", "19,22", "19,24", "19,26", "19,28", "19,30", "19,8", "2,10", "2,11", "2,12", "2,13", "2,14", "2,15", "2,16", "2,18", "2,19", "2,2", "2,20", "2,21", "2,22", "2,23", "2,24", "2,25", "2,26", "2,27", "2,28", "2,29", "2,3", "2,30", "2,31", "2,4", "2,5", "2,6", "2,7", "2,8", "2,9", "20,10", "20,12", "20,14", "20,16", "20,18", "20,2", "20,20", "20,22", "20,24", "20,26", "20,28", "20,3", "20,30", "20,4", "20,5", "20,6", "20,7", "20,8", "21,10", "21,12", "21,14", "21,16", "21,18", "21,20", "21,22", "21,24", "21,26", "21,28", "21,30", "22,10", "22,12", "22,14", "22,16", "22,18", "22,2", "22,20", "22,22", "22,24", "22,26", "22,28", "22,29", "22,3", "22,30", "22,4", "22,5", "22,6", "22,7", "22,8", "22,9", "23,12", "23,14", "23,16", "23,18", "23,2", "23,20", "23,22", "23,24", "23,26", "24,10", "24,11", "24,12", "24,14", "24,16", "24,18", "24,2", "24,20", "24,22", "24,24", "24,26", "24,27", "24,28", "24,29", "24,30", "24,4", "24,5", "24,6", "24,7", "24,8", "24,9", "25,14", "25,16", "25,18", "25,2", "25,20", "25,22", "25,24", "26,10", "26,11", "26,12", "26,14", "26,16", "26,18", "26,2", "26,20", "26,22", "26,24", "26,25", "26,26", "26,27", "26,28", "26,29", "26,30", "26,4", "26,5", "26,6", "26,7", "26,8", "26,9", "27,12", "27,14", "27,16", "27,18", "27,2", "27,20", "27,22", "27,30", "27,4", "28,10", "28,11", "28,12", "28,14", "28,16", "28,18", "28,2", "28,20", "28,22", "28,23", "28,24", "28,26", "28,27", "28,28", "28,30", "28,4", "28,6", "28,7", "28,8", "28,9", "29,14", "29,16", "29,18", "29,20", "29,24", "29,26", "29,28", "29,30", "29,4", "29,6", "3,16", "3,18", "3,2", "3,26", "30,1", "30,10", "30,11", "30,12", "30,13", "30,14", "30,16", "30,17", "30,18", "30,2", "30,20", "30,21", "30,22", "30,24", "30,25", "30,26", "30,28", "30,29", "30,3", "30,30", "30,4", "30,6", "30,7", "30,8", "30,9", "4,10", "4,11", "4,12", "4,13", "4,14", "4,16", "4,18", "4,19", "4,2", "4,20", "4,21", "4,22", "4,23", "4,24", "4,26", "4,27", "4,28", "4,29", "4,3", "4,30", "4,4", "4,5", "4,6", "4,7", "4,8", "4,9", "5,14", "5,16", "5,2", "5,24", "5,30", "6,10", "6,11", "6,12", "6,14", "6,16", "6,17", "6,18", "6,19", "6,2", "6,20", "6,21", "6,22", "6,23", "6,24", "6,26", "6,27", "6,28", "6,3", "6,30", "6,4", "6,5", "6,6", "6,7", "6,8", "6,9", "7,12", "7,14", "7,24", "7,26", "7,28", "7,30", "8,10", "8,11", "8,12", "8,14", "8,15", "8,16", "8,17", "8,18", "8,19", "8,2", "8,20", "8,21", "8,22", "8,24", "8,26", "8,28", "8,3", "8,30", "8,4", "8,5", "8,6", "8,7", "8,8", "8,9", "9,2", "9,22", "9,24", "9,26", "9,28", "9,30"], Array(1..451, {(1) = {2, 22}, (2) = {1, 3}, (3) = {2, 4}, (4) = {3, 5}, (5) = {4, 6}, (6) = {5, 7}, (7) = {6, 8}, (8) = {7, 9}, (9) = {8, 23}, (10) = {24, 446}, (11) = {25}, (12) = {26, 447}, (13) = {27, 448}, (14) = {28, 449}, (15) = {29, 450}, (16) = {30, 451}, (17) = {18, 31}, (18) = {17, 19}, (19) = {18, 20}, (20) = {19, 21}, (21) = {20, 22}, (22) = {1, 21}, (23) = {9, 40}, (24) = {10, 41}, (25) = {11, 42}, (26) = {12, 43}, (27) = {13, 44}, (28) = {14, 45}, (29) = {15, 46}, (30) = {16, 48}, (31) = {17, 49}, (32) = {33, 53}, (33) = {32, 34}, (34) = {33, 35}, (35) = {34, 36}, (36) = {35, 37}, (37) = {36, 38}, (38) = {37, 39}, (39) = {38, 40}, (40) = {23, 39, 54}, (41) = {24, 55}, (42) = {25, 56}, (43) = {26, 57}, (44) = {27, 58}, (45) = {28}, (46) = {29, 47}, (47) = {46, 48}, (48) = {30, 47}, (49) = {31, 59}, (50) = {51, 60}, (51) = {50, 52}, (52) = {51, 53}, (53) = {32, 52}, (54) = {40, 67}, (55) = {41, 68}, (56) = {42, 69}, (57) = {43, 70}, (58) = {44, 71}, (59) = {49, 78}, (60) = {50, 79}, (61) = {81, 82}, (62) = {63, 83}, (63) = {62, 64}, (64) = {63, 65, 84}, (65) = {64, 66}, (66) = {65, 85}, (67) = {54, 86}, (68) = {55, 87}, (69) = {56, 88}, (70) = {57, 89}, (71) = {58, 72}, (72) = {71, 73}, (73) = {72, 74}, (74) = {73, 75}, (75) = {74, 76}, (76) = {75, 77}, (77) = {76, 90}, (78) = {59, 91}, (79) = {60, 92}, (80) = {81, 93}, (81) = {61, 80}, (82) = {61, 94}, (83) = {62, 95}, (84) = {64, 96}, (85) = {66, 97}, (86) = {67, 98}, (87) = {68, 99}, (88) = {69, 100}, (89) = {70, 101}, (90) = {77, 108}, (91) = {78, 109}, (92) = {79, 110}, (93) = {80, 111}, (94) = {82, 112}, (95) = {83, 113}, (96) = {84, 114}, (97) = {85, 115}, (98) = {86, 116}, (99) = {87, 107}, (100) = {88, 117}, (101) = {89, 102}, (102) = {101, 103}, (103) = {102, 118}, (104) = {105, 119}, (105) = {104, 106}, (106) = {105, 120}, (107) = {99, 109}, (108) = {90, 121}, (109) = {91, 107}, (110) = {92, 122}, (111) = {93, 123}, (112) = {94, 124}, (113) = {95, 125}, (114) = {96, 126}, (115) = {97, 127}, (116) = {98, 128}, (117) = {100, 130}, (118) = {103, 133}, (119) = {104, 134}, (120) = {106, 135}, (121) = {108, 137}, (122) = {110, 140}, (123) = {111, 141}, (124) = {112, 142}, (125) = {113, 143}, (126) = {114, 144}, (127) = {115, 145}, (128) = {116, 146}, (129) = {136, 147}, (130) = {117, 131, 148}, (131) = {130, 132}, (132) = {131, 149}, (133) = {118, 150}, (134) = {119, 151}, (135) = {120, 152}, (136) = {129, 138}, (137) = {121, 153}, (138) = {136, 139}, (139) = {138, 140}, (140) = {122, 139}, (141) = {123, 154}, (142) = {124, 184}, (143) = {125, 185}, (144) = {126, 186}, (145) = {127, 187}, (146) = {128, 188}, (147) = {129, 189}, (148) = {130, 190}, (149) = {132, 191}, (150) = {133, 192}, (151) = {134, 193}, (152) = {135, 194}, (153) = {137, 196}, (154) = {141, 201}, (155) = {156, 183}, (156) = {155, 157}, (157) = {156, 158}, (158) = {157, 159}, (159) = {158, 160}, (160) = {159, 161}, (161) = {160, 331}, (162) = {163, 332}, (163) = {162, 165}, (164) = {175, 333}, (165) = {163, 166}, (166) = {165, 167}, (167) = {166, 168}, (168) = {167, 169}, (169) = {168, 170}, (170) = {169, 171}, (171) = {170, 172, 334}, (172) = {171, 173}, (173) = {172, 174}, (174) = {173, 176}, (175) = {164, 178}, (176) = {174, 177}, (177) = {176}, (178) = {175, 179}, (179) = {178, 180}, (180) = {179, 181}, (181) = {180, 182}, (182) = {181, 183}, (183) = {155, 182}, (184) = {142, 202}, (185) = {143, 203}, (186) = {144, 204}, (187) = {145, 205}, (188) = {146, 206}, (189) = {147, 195}, (190) = {148, 207}, (191) = {149, 208}, (192) = {150, 209}, (193) = {151, 210}, (194) = {152, 211}, (195) = {189, 197}, (196) = {153, 212}, (197) = {195, 198}, (198) = {197, 199}, (199) = {198, 200}, (200) = {199, 201}, (201) = {154, 200}, (202) = {184, 213}, (203) = {185, 214}, (204) = {186, 215}, (205) = {187, 216}, (206) = {188, 217}, (207) = {190, 219}, (208) = {191, 220}, (209) = {192, 221}, (210) = {193, 222}, (211) = {194, 223}, (212) = {196, 226}, (213) = {202, 232}, (214) = {203, 233}, (215) = {204, 234}, (216) = {205, 235}, (217) = {206, 236}, (218) = {225, 237}, (219) = {207, 238}, (220) = {208, 239}, (221) = {209, 240}, (222) = {210, 241}, (223) = {211, 224}, (224) = {223, 226}, (225) = {218, 227}, (226) = {212, 224}, (227) = {225, 228}, (228) = {227, 229}, (229) = {228, 230}, (230) = {229, 231}, (231) = {230, 232}, (232) = {213, 231}, (233) = {214, 244}, (234) = {215, 245}, (235) = {216, 246}, (236) = {217, 247}, (237) = {218, 248}, (238) = {219, 249}, (239) = {220, 250}, (240) = {221, 251}, (241) = {222, 252}, (242) = {243, 262}, (243) = {242, 244}, (244) = {233, 243}, (245) = {234, 263}, (246) = {235, 264}, (247) = {236, 265}, (248) = {237, 266}, (249) = {238, 267}, (250) = {239, 268}, (251) = {240, 269}, (252) = {241, 253}, (253) = {252, 254}, (254) = {253, 255}, (255) = {254, 256}, (256) = {255}, (257) = {258}, (258) = {257, 259}, (259) = {258, 260}, (260) = {259, 261}, (261) = {260, 262}, (262) = {242, 261}, (263) = {245, 273}, (264) = {246, 274}, (265) = {247, 275}, (266) = {248, 276}, (267) = {249, 277}, (268) = {250, 278}, (269) = {251, 279}, (270) = {271, 291}, (271) = {270, 272}, (272) = {271, 292}, (273) = {263, 293}, (274) = {264, 294}, (275) = {265, 295}, (276) = {266, 296}, (277) = {267, 297}, (278) = {268, 298}, (279) = {269, 280}, (280) = {279, 281}, (281) = {280, 282}, (282) = {281, 283}, (283) = {282, 284}, (284) = {283, 285}, (285) = {284, 299}, (286) = {287, 300}, (287) = {286, 288}, (288) = {287, 289}, (289) = {288, 290}, (290) = {289, 291}, (291) = {270, 290}, (292) = {272, 303}, (293) = {273, 304}, (294) = {274, 305}, (295) = {275, 306}, (296) = {276, 307}, (297) = {277, 308}, (298) = {278, 309}, (299) = {285, 315}, (300) = {286, 316}, (301) = {302, 320}, (302) = {301, 303}, (303) = {292, 302}, (304) = {293, 321}, (305) = {294, 322}, (306) = {295, 323}, (307) = {296}, (308) = {297, 324}, (309) = {298, 310}, (310) = {309, 311}, (311) = {310, 325}, (312) = {313, 326}, (313) = {312, 314}, (314) = {313, 327}, (315) = {299, 328}, (316) = {300, 329}, (317) = {318, 330}, (318) = {317, 319}, (319) = {318, 320}, (320) = {301, 319}, (321) = {304, 340}, (322) = {305, 341}, (323) = {306, 343}, (324) = {308, 345}, (325) = {311, 348}, (326) = {312, 350}, (327) = {314, 351}, (328) = {315, 354}, (329) = {316, 355}, (330) = {317, 356}, (331) = {161, 365}, (332) = {162, 366}, (333) = {164, 368}, (334) = {171, 374}, (335) = {344}, (336) = {337, 359}, (337) = {336, 338}, (338) = {337, 339}, (339) = {338, 340}, (340) = {321, 339}, (341) = {322, 342}, (342) = {341, 343}, (343) = {323, 342}, (344) = {335, 353}, (345) = {324, 346}, (346) = {345, 347}, (347) = {346}, (348) = {325, 349}, (349) = {348, 350}, (350) = {326, 349}, (351) = {327, 352}, (352) = {351, 354}, (353) = {344, 355}, (354) = {328, 352}, (355) = {329, 353}, (356) = {330, 357}, (357) = {356, 358}, (358) = {357, 359}, (359) = {336, 358}, (360) = {361, 385}, (361) = {360, 362}, (362) = {361, 363}, (363) = {362, 364}, (364) = {363, 386}, (365) = {331, 387}, (366) = {332, 367}, (367) = {366, 369}, (368) = {333, 378, 388}, (369) = {367, 370}, (370) = {369, 371}, (371) = {370, 372}, (372) = {371, 373}, (373) = {372, 389}, (374) = {334, 375}, (375) = {374, 376}, (376) = {375, 377}, (377) = {376, 379}, (378) = {368, 380}, (379) = {377, 390}, (380) = {378, 381}, (381) = {380, 382}, (382) = {381, 383}, (383) = {382, 384}, (384) = {383, 385}, (385) = {360, 384}, (386) = {364, 394}, (387) = {365, 395}, (388) = {368, 399}, (389) = {373, 404}, (390) = {379, 409}, (391) = {392, 415}, (392) = {391, 393}, (393) = {392, 416}, (394) = {386, 417}, (395) = {387, 396}, (396) = {395, 397}, (397) = {396, 398}, (398) = {397, 400}, (399) = {388, 408}, (400) = {398, 401}, (401) = {400, 402}, (402) = {401, 403}, (403) = {402, 404}, (404) = {389, 403, 418}, (405) = {406, 419}, (406) = {405, 407}, (407) = {406, 420}, (408) = {399, 410}, (409) = {390, 421}, (410) = {408, 411}, (411) = {410, 412}, (412) = {411, 413}, (413) = {412, 414}, (414) = {413, 415}, (415) = {391, 414}, (416) = {393, 424}, (417) = {394, 425}, (418) = {404, 435}, (419) = {405, 436}, (420) = {407, 437}, (421) = {409, 439}, (422) = {423, 445}, (423) = {422, 424}, (424) = {416, 423}, (425) = {417, 426}, (426) = {425, 427}, (427) = {426, 428}, (428) = {427, 429}, (429) = {428, 430}, (430) = {429, 432}, (431) = {438, 446}, (432) = {430, 433}, (433) = {432, 434}, (434) = {433, 447}, (435) = {418, 448}, (436) = {419, 449}, (437) = {420, 450}, (438) = {431, 440}, (439) = {421, 451}, (440) = {438, 441}, (441) = {440, 442}, (442) = {441, 443}, (443) = {442, 444}, (444) = {443, 445}, (445) = {422, 444}, (446) = {10, 431}, (447) = {12, 434}, (448) = {13, 435}, (449) = {14, 436}, (450) = {15, 437}, (451) = {16, 439}}), `GRAPHLN/table/3`, 0)

(3)

StyleVertex(G, sprintf("%d,%d",start[]), color="LimeGreen");

StyleVertex(G, sprintf("%d,%d",finish[]), color="Red");

for v in Vertices(G) do
    SetVertexAttribute(G, v,"draw-pos-fixed"=GetVertexAttribute(H,v,"draw-pos-fixed"));
end do;

DrawGraph(G, stylesheet=[vertexshape="square", vertexpadding=10, vertexborder=false, vertexcolor="Black"],  showlabels=false, size=[800,800]);

 

sp := ShortestPath(G, sprintf("%d,%d",start[]), sprintf("%d,%d",finish[]) ):

StyleVertex(G, sp[2..-2], color="Orange");
StyleEdge(G, [seq({sp[i],sp[i+1]}, i=1..nops(sp)-1)], color="Orange");

DrawGraph(G, stylesheet=[vertexshape="square", vertexpadding=10, vertexborder=false, vertexcolor="Black"],  showlabels=false, size=[800,800]);

 

 

 

 

About once a year Advent of Code give you a problem that is a gift if you are using a computer algebra system. This year that day was Day 13. The day 13 problem was one of crazy claw machines.  Each machine has two buttons that can be pressed to move the claw a given number of X and Y positions and a prize at a given position. A buttons cost 3 tokens to press, and B buttons cost 1 token to press, and we are asked to find the minimum number of tokens needed, IF it is possible to reach the prize. The data presented like so:

Button A: X+94, Y+34
Button B: X+22, Y+67
Prize: X=8400, Y=5400

Button A: X+26, Y+66
Button B: X+67, Y+21
Prize: X=12748, Y=12176

...

Some times the input is harder to parse than the problem is so solve, and this might be one of those cases.  I tend to reach for StringTools to take the input apart, but today the right tool is the old school C-style sscanf (after using StringSplit to split at every double linebreak).

machinesL := StringTools:-StringSplit(Trim(input), "\n\n");
machines := map(m->sscanf(m,"Button A: X+%d, Y+%d\nButton B: X+%d, Y+%d\nPrize: X=%d, Y=%d"), machinesL):

Now we have a list of claw machine parameters in the form [A_x, A_y, B_x, B_y, P_x, P_y] and we need to turn those into equations that we can solve. We want the number of A presses a, and B presses b to get the claw to the P_x, P_y position of the claw, it is simple to just write them down:

for m in machines do
   eqn := ({m[1]*a+m[3]*b=m[5], m[2]*a+m[4]*b=m[6]});
end do;

Now because of the discrete nature of this problem, we need our variables a and b to be non-negative integers.  When solving this, I first reached for isolve like this:

tokens := 0;
for m in machines do
   eqn := ({m[1]*a+m[3]*b=m[5], m[2]*a+m[4]*b=m[6]});
   sol := isolve(eqn);
   if sol <> NULL then
      tokens := tokens + eval(3*a+b, sol);
   end if;
end do;

Now, sometimes Advent of Code inputs contain a lot of hidden structure.  I wrote the code above, it worked on the sample input, so I tried it immediately on my real input (about 300 claw machines like the above) and IT WORKED.  But, you might notice that this code does not deal with a couple cases that could have appeared.  In particular, it doesn't check that the solutions are positive.  It also doesn't handle cases where there is more than one possible solution.  The former is easy to check

if sol <> NULL and eval(a,sol) >= 0 and eval(b,sol) >= 0 then

Unfortunately isolve does not handle inequalities, but you could try with solve, but it doesn't save us any checking, because we'd still have to check if the solutions are integers, so we might as well have just solved the equation and then checked if it were a nonnegative integer.

tokens := 0;
for m in machines do
   eqn := {m[1]*a+m[3]*b=m[5], m[2]*a+m[4]*b=m[6], a>=0, b>=0};
   sol := solve(eqn);
   if type(eval(a,sol), integer) and type(eval(b,sol),integer) then
      tokens := tokens + eval(3*a+b, sol);
   end if;
end do;
ans1 = tokens;

In the multiple solution case we get something like {a = 3 - 2*b, 0 <= b, b <= 3/2} which has some great information in it but might be hard to handle programmatically, so let's see what isolve does with those cases to see if it's easier to deal with

> eqn := { 17*a + 84*b = 7870, 34*a + 168*b = 15740 }:
> constr := { a >= 0, b>= 0 }:
> sol := isolve(eqn);
               sol := {a = 458 - 84 _Z1, b = 1 + 17 _Z1}

> constr := eval({ a >= 0, b>= 0 }, sol):
            const := {0 <= 1 + 17 _Z1, 0 <= 458 - 84 _Z1}

> obj := eval(3*a+b, sol);
                         obj := 1375 - 235 _Z1

You can see it's easy to tell if these show up in your input, since your "token" total will have the _Zn variables in it.  Now, since everything is simple and linear here, it seems like you could use solve to find the rational value of _Z1 that makes obj=0 and then take the closest integer but it's not so simple, we actually have to deal with the contraints that a and b be positive too. So, it really just makes sense to bring out the big hammer of Optimization:-Minimize which allows us to directly optimize over just the integers.  So a full solution looks like this:

tokens := 0:
for m in machines do
   eqn := ({m[1]*a+m[3]*b=m[5], m[2]*a+m[4]*b=m[6]});
   sol := isolve(eqn);
   if sol = NULL then
      next;
   end if;
   constr := eval({ a >= 0, b>= 0 }, sol);
   obj := eval(3*a+b, sol);
   if not type(obj, constant) then
      tokens := tokens + Optimization:-Minimize( obj, constr, assume=integer )[1];
   elif andmap(evalb, constr) then
      tokens := tokens + obj; 
   end if;
end do;

But since we're bringing out the big hammer, why not just use Optimization in the first place.  The main reason is that Minimize doesn't simply return NULL when it doesn't work, instead it throws an exception, so we need to find all the exceptions that can occur and handle then with a try-catch, thus:

tokens := 0;
for m in machines do
   eqn := ({m[1]*a+m[3]*b=m[5], m[2]*a+m[4]*b=m[6]});
   try 
       sol := Optimization:-Minimize(3*a+b, eqn, 'assume'='nonnegint')[1];
       tokens := tokens + sol;
   catch "no feasible":
   end try; 
end do;
tokens;

(you can in fact omit the string in the catch: statement, but I can tell you from long experience that that is an excellent way to make your code much much harder to debug)

Alright, so how did people not using Maple solve this problem?  The easiest way to solve it, and the one used by all the cheaters scraping the website and using LLM-based code generators that auto-submit solutions to get into the Top 100, was to just check all possible a, b values in 0..100 and take the values than minimize 3*a+b when reaching the prize coordinates.  That's only feasible because the problem states the 100 is an upperbound for a and b, but it's also very fast (about 1/10 second in Maple):

tokens := 0:
for m in machines do;
sol := infinity;
for i from 0 to 100 do for j from 0 to 100 do
    if i*m[1]+j*m[3]=m[5] and i*m[2]+j*m[4]=m[6] and 3*i+j < sol then
        sol := 3*i+j;
    end if;
end do; end do;
tokens := tokens + ifelse(sol=infinity,0,sol);
end do;

It does not scale at all to part 2 (which modified everything to be bigger by about 10 trillion), and it seems that foiled all the LLM solvers. So, what solutions scaled in languages without integer equation solvers?  Well, the easiest solution is just to solve the general equation using paper and pencil


And you can just hard code that formula in, check that it gives integer values and compute the tokens. As long as you get unique solutions, that looks something like this

solveit := proc(m)
local asol := m[4]*m[5] - m[3]*m[6];
local bsol := m[1]*m[6] - m[2]*m[5];
local deno := m[1]*m[4] - m[2]*m[3];
if deno = 0 then return -2^63; end if; # multiple solution case - not handled
if asol mod deno = 0 and bsol mod deno = 0
   and (   ( deno>=0 and asol>=0 and bsol>=0 ) 
        or ( deno<=0 and asol<=0 and bsol<=0 ) )
then

    return 3*asol/deno+bsol/deno;
else
    return 0;
end if;
end proc:

Which if you have this in Maple, you can impress your friends by auto generating solutions in other languages. Here, for your FORTRAN friends

> CodeGeneration:-Fortran(solveit);

Warning, the following variable name replacements were made: solveit -> cg
       integer function cg (m)
        doubleprecision m(*)
        integer asol
        integer bsol
        integer deno
        asol = int(-m(3) * m(6) + m(4) * m(5))
        bsol = int(m(1) * m(6) - m(2) * m(5))
        deno = int(m(1) * m(4) - m(2) * m(3))
        if (deno .eq. 0) then
          cg = -9223372036854775808
          return
        end if
        if (mod(asol, deno) .eq. 0 .and. mod(bsol, deno) .eq. 0 .and. (0
     # .le. deno .and. 0 .le. asol .and. 0 .le. bsol .or. deno .le. 0 .a
     #nd. asol .le. 0 .and. bsol .le. 0)) then
          cg = 3 * asol / deno + bsol / deno
          return
        else
          cg = 0
          return
        end if
      end

Another way that you might solve this without solve is to use a linear algebra library to solve the linear system.  It works even if you only have a numeric solver, but you have to be careful about checking for integers:

tokens := 0:
for m in machines do
    sol := LinearAlgebra:-LinearSolve(
               Matrix(1..2,1..2,[m[[1,3]],m[[2,4]]], datatype=float), 
               Vector(m[5..6], datatype=float));
    if abs(sol[1]-round(sol[1])) < 10^(-8) and abs(sol[2]-round(sol[2])) < 10^(-8)
       and sol[1] >= 0 and sol[2] >= 0
    then
       tokens := tokens + 3*sol[1]+sol[2];
    end if;
end do;

Finally, a lot of people solved this sort of thing with the Z3 Theorem prover from Microsoft research which is also way more than you need, but it mostly just uses SMTLIB, which we also have in a library for in Maple, and it can just be used in place of solve

tokens := 0;
for m in machines do
   eqn := {m[1]*a+m[3]*b=m[5], m[2]*a+m[4]*b=m[6], a>=0, b>=0};
   sol := SMTLIB:-Satisfy(eqn) assuming a::nonnegint, b::nonnegint;
   if sol <> NULL and type(eval(a,sol), integer) and type(eval(b,sol),integer) then
      tokens := tokens + eval(3*a+b, sol);
   end if;
end do;

Notice that Satisfy handled the multiple solution case just by choosing one of the many solutions. It is possible to get SMTLib to optimize but it is slightly more involved, and this post is already too long. This time, I've put all this work in worksheet: Day13-Primes.mw

The Advent of Code 2024 Day 11 problem featured labeled rocks which duplicate according to simple rules:

  • Rocks labeled 0 turn into 1's
  • Rocks with a even number of digits in the label split into two rocks with the first and last half of the digits
  • Other rocks have their labels multiplied by 2024

Your puzzle task is to count the number of rocks after 25, then 75 iterations of these rules.

For 25 iterations, a very simple recursive count suffices

count := proc(n, s)
local f, l;
    if n = 0 then return 1;
    elif s=0 then return count(n-1,1);
    end if;
    l := length(s);
    if l mod 2 = 0 then
         f := floor( s/10^(l/2) );
         return count(n-1,f) + count(n-1,s-f*10^(l/2));
    else return count(n-1, 2024*s);
    end if;
end proc:

For the puzzle input, a collection of 8 numbers (the stone labels) the largest with 7 digits, you can call count(25,s) on each s in the input and add them together in about 1 second, but trying that for 75 "hangs" and clearly will not work.

Generally for something like this, the first trick in my puzzle solving toolbox is memoization, so that the results of recursive calls are stored so they don't have to be recomputed.  In Maple, there are two main ways to add memoization to recursive procedures: option cache and option remember.  The remember option is older and uses a simple table that gets populated with (input,return) pairs whenever the procedure returns. The cache option is newer and uses size limited LRU tables that are more memory friendly.  Typically in the Maple math library we use cache tables since they won't fill up your working memory with cached results, and will remove old cached elements in a smart way (the double option option remember, system also limits table growth by allowing entries to be garbage collected, but it is not as flexible as a cache).

So this preable is to say, that the first memoization option I tend to reach for is option cache but best practice for Maple math library development is not always the thing that solves a code puzzle.  In this case, adding option cache to our procedure count also "hangs".  If you are smart, you will immediately try again with option remember, and you'll find that works easily:

count := proc(n, s)
option remember;
    if n = 0 then return 1;
    elif s=0 then return count(n-1,1);
    end if;
    local l := length(s);
    if l mod 2 = 0 then
         local f := floor( s/10^(l/2) );
         return count(n-1,f) + count(n-1,s-f*10^(l/2));
    else return count(n-1, 2024*s);
    end if;
end proc:
ans1 := CodeTools:-Usage( add( map2(count, 25, input) ) ); # 17ms
ans2 := CodeTools:-Usage( add( map2(count, 75, input) ) ); # 825ms

So why does remember work, when cache fails so spectacularly? Well, you can create a function with a cache, call it once create it and the examine the Cache object with op:

> cacheFunc := proc() option cache; args; end proc:
> cacheFunc(1): op( 4, eval(cacheFunc) );

                       Cache(512, 'temporary' = [1 = 1])

You can see here that the default cache is 512 entries which is a pretty good default for general use, but way way too small for this ridiculous puzzle problem.  Fortunately, the cache option allows you to specify a size to create a much bigger cache for a highly recursive procedure like this one.  I tested caches of various sizes (cache always rounds up the next power of 2) and compared to option remember and remember, system.

  1. option remember  - 707ms
  2. option remember, system - 4.22s
  3. option cache  - too slow, killed after hours
  4. option cache(1024) - 30.21s
  5. option cache(16384) - 5.60s
  6. option cache(131072)- 726ms
  7. option cache(1048576)- 806ms

So, for this problem, it looks like a 2^17=~100,000 entry cache (#6) gives about the same performance as a remember table, so it's not surpring a larger cache does no better. 

In fact, since results are not removed from an option remember table, you can actually check exactly how many results were cached and see it is just less than 2^17.

> add( map2(count, 75, input) ): numelems( op(4, eval(count) ) );
                                    120076

And the take away is, for this sort of puzzle solving you should try option remember even if option cache is usually a better choice when implementing a more serious mathematical algorithmn that wants to occasionally needs to reuse results.

Every December since 2015, software engineer and puzzle enthusiast Eric Wastl has created an Advent Calender of code challenges called Advent of Code. These puzzles can be solved in any programming language, since you are only required to submit a string or integer solution, and tend to increase in difficulty over the course of the 25 days. Each puzzle has two parts each using the same input (which is different for each user), the second part being revealed only after the first part is solved.

I started participating in this puzzle challenge in 2021 and I like to solve them using Maple right when they are unlocked at 12am EST each day. I post my my solutions to my github as Maple worksheets, and (usually) later as cleaned up Maple text files: https://github.com/johnpmay/AdventOfCode2024

I typically work in a Maple worksheet since I find the worksheet interface ideal to quickly play with an evolving piece of code to solve a puzzle (it is kind of a race if you want it to be, Advent of Code tells you your place every day and gives you "points" if you are one of the first 100). Also I find the nature of the Maple language and its variety of libraries pretty ideal for approaching these problems.

Today, I am writing about this because 2025 Day 5 was a cool puzzle that really asked to be analyzed further in Maple. (Note, if you are participating in Advent of Code and haven't solved Day 5, there are heavy spoilers ahead).

Once you decypher the silly story about the elves, the problem comes down to a set of pairwise ordering rules, and a collection of lists (called updates) that need to be checked if they are sorted according to the rule. This seems straightforward, but as always you have a (big!) input file to handle.  In this case the input looks like this (the actual input not included here, but it's much much longer)

75|13
53|13
[...elided...]


75,47,61,53,29
97,61,53,29,13
[...elided...]

For this step, StringTools is your best friend (I typically read in the whole input as a string using FileTools:-Text:-ReadFile).  I first use StringSplit on the double line break "\n\n" to seperate the rules from the updates.  Then I map an ordinary Split over those to make everything into nested lists of integer.

(rules, updates) := StringSplit(Trim(input), "\n\n")[]:
rules := map(s->map(s2i,Split(s,"|")), Split(rules,"\n")): 

        rules := [[75, 13], [53, 13], ...]

updates := map(s->(map(s2i,Split(s,","))), Split(updates, "\n")):

        updates := [[75, 47, 61, 53, 29], [97, 61, 53, 29, 13], ...]

(the function s2i is a "string to integer" helper function since it's considered bad practice to just call parse on input handed to you by a stranger on the internet.  In older version of maple I used: s2i := s->sscanf(s,"%d")[1] in newever versions you can use the way less cryptic s2i := s->convert(s,'integer') )

Okay, now that we have two nice lists, it's easy to check which of the updates is sorted according to the rules with a simple nested loop.

goodups := DEQueue():

for u in updates do
    for r in rules do
        if member(r[1],u,'i') and member(r[2],u,'j') then
           if j < i then next 2; end if;
        end if;
     end do;
     push_back(goodups, u);
end do:

For each update, check that if a rule applies to it then that rule is obeyed. If the rule r is violated, advance the outer loop with the relatively new and useful next 2; syntax (it also works with break #) and if not check the next rule. If no rules were violated then push u into our stack of Good Updates.  This is a perfectly fine solution to part 1 of the puzzle, but if you thing about it a little why not just use sort with a custom comparision function built from the rules?

V := ListTools:-MakeUnique(map2(op,1,rules)): # all the numbers that can appear
N := [seq(map2(op,2,select(n->m=n[1], rules)), m in V)]: # all their neighbors in the graph induced by rules
T := table([seq(V[i]={N[i][]}, i=1..nops(V))]): # table of neighbors
comp := (x,y)->evalb(y in T[x]): # "less than" according the rules

Now with that comp function we can just do

goodups := select(u->sort(u, comp)=u, updates);

to find all the correctly sorted updates, this will seem like a better idea when you get the [SPOILER] part 2 of the problem which is to sort all the incorrectly sorted updates.

NOW WAIT A MINUTE.  If you look at the fine help page for ?sort you'll see it very clearly says about the comp function F (emphasis added):

custom boolean procedure

 When F does not match one of the symbols listed above, it must be a Boolean-
 valued function of two arguments.  Specifically, F(a,b) returns false if and  
 only if b must precede a in the sorted output.  That is F(a,b) is a non-
 strict less than comparison function.  In addition, F(a,b) must be defined  
 for all pairs a for a and b in the input structure and F(a,b) must be  
 transitive
, that is, if F(a,b) = true and F(b,c) = true then F(a,c) = true.

Dear reader, I guess we should check if our rules from the puzzle create a relation that is transitive.  The good news is that the sample input given in the problem description is indeed transitive. The easiest way I could think to check that was to use GraphTheory and see if there were any cycles in the directed graph given by the rules. So, let's make a graph with an edge for every comparison rule a<b, b<c, etc.  If there is a cycle in the graph, that will be a case where a < b < c < a in our rules and therefore non-transitivity in the comparison.  When we do that, we see it's cycle-free.

with(GraphTheory):
G := Graph({rules[]});
FindCycle(G); # returns []

That graph is really nice, it looks like this:

If you count the in-degree of each vertex, you can see it actually induced a total order on the numbers going linearly from smallest to largest numbers.

So, is that also true of the actual input you are given? Of course not. When you create the graph of your actual puzzle input you find there is a 3-cycle.

with(GraphTheory):
G := Graph({rules[]});
FindCycle(G); # returns a 3-cycle
seq(FindCycle(G,v),v in Vertices(V)); # returns a 3-cycle for every v!

In fact, there is a 3-cycle from every single vertex.  But at least the graph is pleasing to contemplate. Let it calm you:

So, does this mean sort with out comp function doesn't work? Is all lost? In fact, I solved both parts of the puzzle using a custom comparision for sort before stopping to consider that maybe the comparison wasn't transitive. And... it just works! So, WHY does it work? (the comparison is very very non-transitive). The answer is of course that the lists you need to sort don't contain all of the numbers covered by the rules.  In fact, your clever/cruel puzzlemaster has in fact constructed each of those (200 or so) lists so that it misses every one of the 3-cycles in the above graph. You can carefully check that by restricting the relation graph to the subset of numbers in each list and check for cycles:

G := Graph({rules[]});
H := InducedSubgraph(G, updates[i]); # try for i=1..nops(updates)
FindCycles(H); # returns [] for every element of update

In fact, each of those induced subgraphs looks like this

and you can maybe observe that this induced a total order on the numbers in the problem. Or if you are not careful, and you didn't bother to check, you would get the right answer anyway. Because it's only Day 5, and Eric Wastl hasn't decided to make thing really challenging yet.

I hope you've enjoyed my deep dive into this problem. And I hope it's inspired you to go try out Advent of Code. It's a fun challenge. Let me know in a comment if you're participating! Maybe we can start a leaderboard for MaplePrimes folks working on the puzzles.

1 2 3 4 5 6 7 Last Page 1 of 27